Revel框架中静态资源必须通过路由GET /public/*filepath Static.Serve接管,而非http.FileServer直接暴露,否则压缩、ETag、缓存等中间件全部失效;需配合app.conf配置static.dir、模板动态注入resourceVersion及Nginx路径透传。

Revel 框架默认把静态资源放在 public 目录下,但直接用 http.FileServer 暴露该目录会导致所有 Revel 中间件(压缩、ETag、缓存头)全部失效——这是最常被踩的坑。
必须通过 Revel 路由接管 /public/*filepath
不能在 app/init.go 里写 http.Handle("/public/", http.FileServer(...)),否则请求绕过 Revel 生命周期。正确做法是:在 conf/routes 文件末尾添加一条路由规则:
GET /public/*filepath Static.Serve
这条规则让 Revel 自带的 Static.Serve 控制器处理所有 /public/ 开头的请求,从而保留 filter 链(如压缩、缓存控制、版本注入等)。
-
Static.Serve默认服务public目录下的文件,路径映射是严格按文件系统结构来的(例如请求/public/css/app.css对应磁盘上public/css/app.css) - 若想换根目录(比如改成
assets),需在app.conf中配置:static.dir = assets - 该路由必须放在
routes文件靠后位置,避免被前面的通配路由(如* / catchall)拦截
静态资源 URL 在模板中怎么写才不硬编码
Revel 没有内置资源哈希或指纹功能,但可通过拦截器注入版本号,再拼到 URL 查询参数中。关键点在于:不要手写 /public/js/main.js?v=1.2.0,而要动态生成。
- 在拦截器中从
app.conf读取resourceVersion并注入模板上下文:c.RenderArgs["resourceVersion"] = revel.Config.StringDefault("resourceVersion", "1") - 模板中统一使用:
<script src="/public/js/main.js?v=%7B%7B.resourceVersion%7D%7D"></script> - 构建时用 CI 设置
resourceVersion = {{.CommitSHA}}或{{.BuildTime}},避免每次手动改配置
Nginx 反向代理时,/public 路径别被截断
如果用 Nginx 做反向代理,且前端路径带子路径(如部署在 https://example.com/myapp/),Nginx 的 location 配置容易把 /public/ 前缀吃掉,导致 Revel 收到的 filepath 不完整。
- 错误写法(会丢掉
/public):location /myapp/ { proxy_pass http://127.0.0.1:8089/; } - 正确写法(保留原始路径):
location /myapp/ { proxy_pass http://127.0.0.1:8089/; proxy_redirect off; },并确保 Revel 应用内部也识别子路径(通过app.conf设置app.path = /myapp) - 更稳妥的做法:让 Nginx 把
/public/请求直接本地服务,不走 Revel(需同步配置location /public/+root),但此时要手动加Cache-Control和ETag头
真正麻烦的不是怎么配路径,而是路径背后那条链:从 Nginx 到 Revel 路由、再到模板渲染、最后到浏览器缓存行为,任何一环断开,都会让 /public/xxx 看似能访问,实则不走压缩、不更新缓存、甚至返回 404 却查不出原因。


















