Revel全站Gzip压缩需同时满足三条件:配置启用(results.compressed=true)、过滤器注册(results.compression.filter=true或手动InterceptMethod)、响应符合压缩前提(状态码非204/304、MIME在白名单、含Accept-Encoding:gzip、非空且超阈值);静态资源须走Revel路由而非直连http.FileServer,避免被Nginx重复压缩。

Revel 框架的全站 Gzip 压缩不是开个开关就自动生效的,它依赖三重条件同时满足:配置启用、过滤器注册、响应符合压缩前提。多数人卡在“明明配了却没看到 Content-Encoding: gzip”——问题几乎都出在这三处。
确认 CompressFilter 是否真正加载进请求链
仅在 conf/app.conf 里设 results.compressed = true 不够,CompressFilter 必须被显式注册到 filter 链中:
-
conf/app.conf中必须同时存在:results.compressed = true且results.compression.filter = true - 若项目重写了
app.Init(),需手动注册:revel.InterceptMethod(app.Compress, revel.BEFORE) - 启动时日志里应出现
CompressFilter installed;没有则说明 filter 未加载,压缩逻辑根本不会运行
检查响应是否被 CompressFilter 跳过
即使 filter 加载成功,CompressFilter 也会主动跳过以下响应:
- 状态码为
204或304(HTTP 规范明确禁止对这两类响应压缩) - 响应 MIME 类型不在
compressableMimes白名单内,例如默认不含application/wasm、font/woff2、image/svg+xml - 客户端请求头缺失
Accept-Encoding: gzip(常见于某些测试工具或旧版爬虫) - 响应体为空或长度小于阈值(Revel 默认不压缩极小响应)
可在浏览器 DevTools 的 Network 面板筛选 text/css 或 application/javascript,逐个检查 Response Headers 中是否有 Content-Encoding: gzip;若没有但 Content-Length 明显变小,可能是 Nginx 预压缩覆盖了 Revel 行为。
静态资源路径必须走 Revel 路由,不能直连 http.FileServer
这是最容易被忽略的一点:如果你用 http.FileServer 直接暴露 dist/ 目录,所有 Revel filter(包括压缩、ETag、Cache-Control)全部失效。
- 错误做法:
revel.Static("/static", http.Dir("dist"))是无效的,它只是快捷注册一个http.FileServerhandler - 正确做法:定义路由
GET /public/*filepath {app.Static},并在app.Static方法中调用revel.Static或手动读取文件并写入c.Response.Out - 更稳妥方式:用
revel.Static注册的路径必须匹配 Revel 的 router,例如GET /assets/*filepath {app.ServeAsset},再在app.ServeAsset中做 MIME 判断和压缩委托
避免与 Nginx 等反向代理重复压缩
Go 层动态压缩 + Nginx 再压一次,不仅浪费 CPU,还可能导致解压失败或体积不降反升。
- 若用 Nginx,推荐关掉 Revel 压缩,改用
gzip_static on+ 构建时预生成.gz文件(如 Webpack 的compression-webpack-plugin) - 若坚持用 Revel 压缩,务必在 Nginx 配置中关闭
gzip on,并确保其gzip_types不与 Revel 冲突 - 在
compress.go的shouldCompress函数中加判断:if filepath.Ext(path) == ".gz" { return false },防止已压缩文件被二次处理
真正起作用的从来不是“开了压缩”,而是你是否让每个字节都经过了 CompressFilter 的判定路径——尤其是那些你以为“肯定被压了”的 CSS 和 JS 文件,它们往往正从 FileServer 的后门溜走。


















