【问题标题】:How to serve static files from root URL如何从根 URL 提供静态文件
【发布时间】:2021-08-24 08:32:32
【问题描述】:

我正在使用 http/server 制作简单的 Web 应用程序,并使用以下代码来处理路由(归功于 post):

package retable

import (
    "context"
    "fmt"
    "net/http"
    "regexp"
    "strconv"
    "strings"
)

var routes = []route{
    newRoute("GET", "/", home),
}

func newRoute(method, pattern string, handler http.HandlerFunc) route {
    return route{method, regexp.MustCompile("^" + pattern + "$"), handler}
}

type route struct {
    method  string
    regex   *regexp.Regexp
    handler http.HandlerFunc
}

func Serve(w http.ResponseWriter, r *http.Request) {
    var allow []string
    for _, route := range routes {
        matches := route.regex.FindStringSubmatch(r.URL.Path)
        if len(matches) > 0 {
            if r.Method != route.method {
                allow = append(allow, route.method)
                continue
            }
            ctx := context.WithValue(r.Context(), ctxKey{}, matches[1:])
            route.handler(w, r.WithContext(ctx))
            return
        }
    }
    if len(allow) > 0 {
        w.Header().Set("Allow", strings.Join(allow, ", "))
        http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed)
        return
    }
    http.NotFound(w, r)
}

type ctxKey struct{}

func getField(r *http.Request, index int) string {
    fields := r.Context().Value(ctxKey{}).([]string)
    return fields[index]
}

func home(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "home\n")
}

如果此端点上已存在其他路由注册,如何从“/”端点上的本地“static/”文件夹提供静态文件?

【问题讨论】:

  • 请注意,您的自定义路由器的性能会非常差,因为它只是通过正则表达式匹配对已注册的路由进行简单循环。但总的来说,只要您有办法将这些请求与其他请求区分开来,就可以确保您可以从根目录提供静态文件,这一切都只是路由。

标签: go go-http


【解决方案1】:

正如所写,您的代码期望与构建路由时提供的模式完全匹配。 (构造正则表达式时请参阅^$。)因此您将无法在/-pattern 的处理程序中处理/static/ 请求。

如果您对现有代码进行更改,您也许能够实现您想要的。下面的一些选项。

选项 1

routes中包含静态模式:

var routes = []route{
    newRoute("GET", "/", home),
    newRoute("GET", "/static/(.+)", static),
}

定义一个示例static HTTP 处理函数:

func static(w http.ResponseWriter, r *http.Request) {
    log.Println("received static request for ", getField(r, 0))
}

您可能希望使用以下组合来促进提供静态文件:

  • http.StripPrefix
  • http.FileServer
  • http.Dir / http.FS,与 embed 配合得很好

选项 2

修改newRoute 以在构造正则表达式时不使用^$。但是,这可能会影响代码中其他地方的期望。特别是,/ 模式将匹配所有请求,因此routes 切片的顺序变得很重要。

    return route{method, regexp.MustCompile(pattern), handler}

然后在home:

func home(w http.ResponseWriter, r *http.Request) {
    if strings.HasPrefix(r.URL.Path, "/static/") {
        log.Println("received static request", r.URL.Path)
        // TODO: actually respond with file
        return
    }
    fmt.Fprint(w, "home\n")
}

脚注

作为脚注,我建议使用 http.ServeMux / http.DefaultServeMux 而不是您的 Serve 实现。这些都是经过实战考验的,可能会更高效,并且可能比您的代码没有那么令人惊讶的行为。

例如,http.ServeMux/http.DefaultServeMux 清理路径,问题中的代码没有这样做。因此,例如,使用问题中的原始代码,请求

curl localhost:8080//

由于双斜杠而不是到达 home 处理程序,将导致 404。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多