正确做法是:用 static.New() 显式注册为独立 Handler,必须前置防盗链等中间件、启用安全模式防路径遍历、校验目录存在性、手动配置缓存头与 MIME,并确保 URL 前缀与挂载点完全匹配。

直接挂载 static.New() 就能服务静态文件,但默认行为不校验 Referer、不设缓存头、不处理路径遍历——生产环境必须手动加固。
怎么用 static.New() 正确挂载静态资源
它不是中间件,而是独立的 Handler,必须显式注册到路由;路径前缀要和实际 URL 一致,否则 404。
-
app.Use("/assets", static.New("./public/assets"))表示访问/assets/logo.png会读取本地./public/assets/logo.png - 路径前缀(如
/assets)必须和static.New()的挂载点完全匹配,不能漏掉尾部斜杠或写成/assets/(后者会导致子路径失效) - 目录路径必须是相对当前工作目录的路径,不是相对于
go.mod或源码文件的位置;建议用绝对路径避免歧义:filepath.Join(os.Getenv("PWD"), "public", "assets") - 若目录不存在,
static.New()不报错,但所有请求返回 404 —— 需自行加os.Stat检查
为什么 static.New() 默认不防路径遍历
它底层调用 fasthttp.FS,默认开启 Compress: true 和 Index: "index.html",但 SafeNavigation 是 false —— 这意味着 ../../../etc/passwd 这类路径会被原样解析。
- 必须手动启用安全模式:
static.New("./public").EnableDirListing(false).Browse(false) - 更稳妥的做法是禁用目录浏览 + 显式过滤非法字符:
strings.Contains(c.Path(), "..")在中间件里提前拦截 - 不要依赖前端路径 sanitize,攻击者可绕过 JS 直接发恶意请求
防盗链中间件必须在 static.New() 之前注册
顺序错了就等于没加——Fiber 请求生命周期中,static.New() 是终结型 handler,一旦命中就直接返回文件,后续中间件不再执行。
- 正确顺序:
app.Use("/assets", refererMiddleware); app.Use("/assets", static.New("./public/assets")) - 错误顺序:
app.Use("/assets", static.New("./public/assets")); app.Use("/assets", refererMiddleware)→ 中间件永远不会触发 - Referer 解析必须用
url.Parse(c.Get("Referer"))取.Hostname(),不能字符串匹配;空 Referer(如书签、微信内嵌)需显式允许或拒绝,取决于业务场景 - 白名单建议用
map[string]struct{},比如allowedHosts := map[string]struct{}{"my.com": {}, "localhost": {}, "127.0.0.1": {}}
缓存头和 MIME 类型容易被忽略
static.New() 不自动设置 Cache-Control 或 ETag,浏览器每次都会重请求;MIME 类型也只靠扩展名推断,JS/CSS 文件若后缀不对可能被当成 text/plain 而阻塞执行。
- 通过
static.Config手动配置:static.New("./public").MaxAge(3600).Compress(true) - 自定义 MIME 映射需改全局
fasthttp.MimeXML,但更推荐确保文件后缀标准(如.js、.css) - 开发时可加
Next: func(c *fiber.Ctx) bool { return c.Hostname() == "localhost" }让本地请求跳过缓存
最常漏掉的是挂载顺序和 Referer 解析的 panic 防御——c.Get("Referer") 可能为空或非法格式,url.Parse() 会 panic,必须先判空再解析。


















