go - 如何从根 URL 提供静态文件
问题描述
我正在使用 http/server 制作简单的 Web 应用程序,并使用以下代码来处理路由(归功于这篇文章):
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/”文件夹提供静态文件?
解决方案
如所写,您的代码期望与构建路由时提供的模式完全匹配。(在构造正则表达式时请参阅^
and $
。)因此您将无法在-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
clean 路径,问题中的代码没有这样做。因此,例如,使用问题中的原始代码,请求
curl localhost:8080//
由于双斜杠而不是到达处理程序,将导致 404 home
。
推荐阅读
- c++ - 调用函数时的 C++ 未定义引用
- html - 不知何故,我无法覆盖 normalize.css?
- flutter - 如何检测我的 Flutter 应用程序是否在 Web 中运行?
- excel - 第二高值
- google-contacts-api - Google 搜索广告价格自动化脚本
- python - 具有两个具有 nan 值的数组的 Pearsonr
- android - 当我生成签名的 apk 时,将错误的数据保存到 Firebase 数据库
- phaser-framework - 如何检查鼠标是否在移相器 3 中的游戏对象上?
- kotlin - 获取哈希映射
> 在 MVVM+Repostiory+LiveData 设置中? - python - 从python3中树结构对象的内存中删除