如何在Go中从embed嵌入文件系统提供指定文件并执行前置校验逻辑
错误原因
你调用的http.ServeFile默认读取的是操作系统本地磁盘的文件,无法读取通过//go:embed编译进二进制程序的嵌入文件系统,所以会返回404错误。
解决方法
你可以从嵌入的文件系统中读取目标文件后返回,两种常用实现方式如下:
方式1:直接操作嵌入文件系统返回内容
首先将你之前通过fs.Sub得到的static目录子文件系统注入到你的Handler结构体中:
type Handler struct { Service // 你原有业务服务实例 StaticFS fs.FS // 存储static目录的嵌入子文件系统 } // 初始化Handler时传入你已生成的fSys // fSys, _ := fs.Sub(static, "static") // h := Handler{StaticFS: fSys}
之后修改你的路由处理函数:
func (h Handler) ServeSignPage(w http.ResponseWriter, r *http.Request) error { publicKey := r.URL.Query().Get("publicKey") err := h.Service.AuthorizeClientSigning(r.Context(), publicKey) if err != nil { return err } // 从嵌入文件系统打开sign.html f, err := h.StaticFS.Open("sign.html") if err != nil { http.NotFound(w, r) return err } defer f.Close() // 获取文件元信息,用于设置响应头、支持缓存等特性 fi, err := f.Stat() if err != nil { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return err } // 标准静态文件返回,支持断点续传、缓存校验等能力 http.ServeContent(w, r, fi.Name(), fi.ModTime(), f) return nil }
如果你不想额外注入StaticFS,也可以直接操作全局的embed.FS变量,路径写全即可:
// 直接用全局的static embed.FS打开文件 f, err := static.Open("static/sign.html")
方式2:复用静态文件服务逻辑(更简洁)
权限校验通过后临时修改请求路径,复用已有的http.FileServer逻辑返回文件:
func (h Handler) ServeSignPage(w http.ResponseWriter, r *http.Request) error { publicKey := r.URL.Query().Get("publicKey") err := h.Service.AuthorizeClientSigning(r.Context(), publicKey) if err != nil { return err } // 临时修改请求路径为静态文件路径 r.URL.Path = "/sign.html" // 复用静态文件服务能力返回内容 http.FileServer(http.FS(h.StaticFS)).ServeHTTP(w, r) return nil }
内容的提问来源于stack exchange,提问作者Ado Ren
相关产品推荐
相关产品推荐

