fiber静态文件默认不缓存,因底层http.fileserver未设cache-control,返回no-cache;需显式配置static中间件的cachecontrol选项,推荐使用fiber.static{cachecontrol: "public, max-age=31536000, immutable"}。

Fiber 默认不自动设置静态资源缓存头,必须显式配置 Static 中间件的 CacheControl 选项,否则所有静态文件(.js、.css、.png 等)都返回 Cache-Control: no-cache —— 这是生产环境常见性能陷阱。
为什么 Fiber 静态文件默认不缓存
Fiber 的 app.Static() 底层用的是 http.FileServer,而 Go 标准库对静态文件的处理默认不设 Cache-Control,实际响应头里会带 Cache-Control: no-cache(或空),浏览器每次都会重新请求。这不是 bug,是 Go 的保守设计:避免开发者误缓存动态内容。
你看到的“没生效”,大概率不是配置错,而是压根没配。
- 不设
CacheControl→ 响应头无Cache-Control或值为no-cache - 设了但值写成
"public, max-age=0"→ 效果等同于不缓存 - 用
app.Use(func(c *fiber.Ctx) {...})手动写头,但放在Static之后 → 被中间件覆盖,无效
正确设置 Cache-Control 的两种方式
必须在调用 app.Static() 时传入配置对象,不能事后补。推荐用第一种:
✅ 推荐写法(明确控制):
app.Static("/static", "./public", fiber.Static{
CacheControl: "public, max-age=31536000, immutable",
})
⚠️ 注意:immutable 表示资源永不变更,配合文件名哈希(如 main.a1b2c3.js)才安全;若用原始文件名,别加 immutable。
✅ 替代写法(按扩展名差异化):
app.Static("/static", "./public", fiber.Static{
CacheControl: "public, max-age=604800",
// 只对特定后缀启用 long-term 缓存
Compress: true,
})
然后用 app.Get("/static/*", ...) 拦截并重写头(不推荐,增加路由开销)。
容易踩的坑:ETag 和 Last-Modified 不生效
Fiber 的 Static 默认开启 ETag 和 Last-Modified,但它们依赖文件系统 mtime 和内容哈希。如果部署时用了 rsync 或容器镜像构建,可能因文件时间戳被重置或 inode 变化导致 ETag 总变 —— 浏览器无法复用缓存。
- 检查响应头是否真有
ETag:curl -I https://yoursite/static/main.js - 若 ETag 是
"-123456789"这类数字,说明只基于 mtime,不稳定;若含哈希(如"W/"abc123""),才可靠 - 强制禁用 ETag(仅当确认不需要):
fiber.Static{DisableETag: true}
CDN 场景下要额外加 Vary 头
如果你前端套了 CDN(如 Cloudflare、又拍云),且静态资源做了 Brotli/Gzip 压缩,CDN 需区分压缩版本缓存,否则可能把 gzip 响应返回给不支持的客户端。
此时不能只靠 CacheControl,得手动加 Vary:
app.Get("/static/*", func(c *fiber.Ctx) error {
c.Set("Vary", "Accept-Encoding")
return c.Next()
})
注意:这个 Get 路由必须放在 app.Static() 之前,否则不生效。
真正难的不是写那行 CacheControl,而是想清楚哪些资源该长期缓存、哪些要随版本更新、哪些连 CDN 都不该缓存(比如 /static/config.json)。Fiber 把选择权留给你,但不会替你做判断。











