Nginx反向代理需先压缩再缓存,通过启用gzip模块、配置gzip_vary on、在proxy_cache_key中加入$http_accept_encoding,并合理设置gzip_proxied,实现按编码版本缓存压缩响应。

要让 Nginx 在反向代理场景下正确缓存已压缩的响应,关键不是“先缓存再压缩”,而是确保压缩发生在缓存写入之前,并让缓存能识别、区分和复用不同编码版本的内容。否则,每次请求都会重新压缩,白白消耗 CPU,也浪费带宽。
确认 gzip 模块已启用且配置合理
运行 nginx -V 2>&1 | grep -o with-http_gzip_module,有输出才说明模块存在。若无,需重新编译并添加 --with-http_gzip_module 参数。
在 http 块中统一配置基础压缩行为:
- gzip on; —— 必须开启
- gzip_min_length 1024; —— 跳过小响应,避免负收益
- gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml; —— 明确列出文本类 MIME 类型;不加图片、字体等二进制格式
- gzip_vary on; —— 强制响应头包含 Vary: Accept-Encoding,这是后续多版本缓存的前提
- gzip_comp_level 4; —— 平衡速度与压缩率,生产环境不建议用 9
设置 proxy_cache 支持按编码缓存
仅开启 gzip 不足以让压缩内容被缓存。Nginx 默认只根据 $scheme$host$request_uri 缓存,若不处理 Vary 头,所有客户端(无论是否支持 gzip)都会拿到同一份缓存,导致未压缩用户收到乱码,或压缩用户拿到原始大体积内容。
需在 location 块中启用缓存并显式继承 Vary 逻辑:
- proxy_cache mycache;
- proxy_cache_key $scheme$host$request_uri$is_args$args$accept_encoding; —— 或更稳妥地使用 $scheme$host$request_uri$is_args$args$http_accept_encoding,确保编码差异参与 key 计算
- proxy_cache_valid 200 302 10m;
- proxy_ignore_headers Cache-Control Expires Set-Cookie; —— 防止后端响应头强制禁用缓存(按需启用)
代理场景下控制何时压缩:用好 gzip_proxied
当 Nginx 作为反向代理时,后端返回的响应可能带 Cache-Control: no-cache 或 Authorization 头——这类内容不适合公共缓存,但体积大、值得压缩传输。
gzip_proxied 就是为此设计的判断开关:
- gzip_proxied no-cache no-store private expired auth; —— 表示当上游响应含这些头之一时,才启用 gzip 压缩
- 它不控制缓存,只控制“是否对这个代理响应做压缩”,配合 gzip_vary on 和带 Accept-Encoding 的 cache key,就能实现“动态内容也压缩、且可缓存”
- 避免设为 any 或 off,前者易误压已压缩资源,后者则完全跳过压缩机会
验证是否真正生效
上线后别只看配置,要用真实请求验证:
- 用 curl -H "Accept-Encoding: gzip" -I https://yoursite.com/test.js 查看响应头是否有 Content-Encoding: gzip 和 Vary: Accept-Encoding
- 两次请求相同 URL,一次带 Accept-Encoding: gzip,一次不带,检查 X-Cache: HIT 是否分别命中(需在 proxy_cache 中加 add_header X-Cache $upstream_cache_status;)
- 对比响应体大小,确认压缩确实发生且未被绕过


















