gzip_vary on的核心作用是让缓存系统依据Accept-Encoding区分响应变体,Nginx通过自动添加Vary: Accept-Encoding头实现缓存键隔离,而非自行验证缓存有效性;生效后,带/不带gzip的请求将被缓存为独立条目。

开启 gzip_vary on 后,Nginx 本身不主动“验证”缓存有效性,而是通过标准 HTTP 缓存协商机制,让上游缓存(如 CDN、代理、浏览器)正确区分和存储不同编码版本的响应。关键在于它改变了缓存键(cache key)的判断依据,而非自行校验。
核心作用:让缓存系统知道“压缩与否”是内容差异
当 gzip_vary on 生效时,Nginx 会在响应头中自动添加:
Vary: Accept-Encoding
这个头部明确告诉所有中间缓存:同一 URI 的响应是否可复用,取决于客户端请求头中的 Accept-Encoding 值是否一致。例如:
- 客户端 A 请求带
Accept-Encoding: gzip→ Nginx 返回 gzip 压缩内容,并打上Vary: Accept-Encoding - 客户端 B 请求带
Accept-Encoding: identity(即不要压缩)→ Nginx 返回未压缩内容,同样带Vary: Accept-Encoding - 缓存系统看到
Vary字段后,会把这两个响应视为两个独立缓存项,不会混用
如何确认机制已生效
不依赖日志或内部状态,直接检查实际 HTTP 交互:
- 用
curl -H "Accept-Encoding: gzip" -I https://example.com/style.css查看响应头,确认含Vary: Accept-Encoding且Content-Encoding: gzip - 再用
curl -H "Accept-Encoding: identity" -I https://example.com/style.css,确认仍含Vary: Accept-Encoding,但无Content-Encoding头,且Content-Length明显更大 - 若两次响应都被缓存(如经 CDN),且各自返回正确内容,说明
Vary已被尊重,缓存隔离有效
常见失效场景与排查点
即使开了 gzip_vary on,缓存仍可能错乱,通常源于外部干扰:
-
CDN 或反向代理覆盖/忽略 Vary:部分 CDN 默认不缓存带
Vary: Accept-Encoding的响应,或强制合并;需在 CDN 控制台启用 “Vary-aware caching” 或等效选项 -
后端应用手动覆写 Vary 头:比如 PHP 脚本执行
header('Vary: User-Agent'),会覆盖 Nginx 添加的Vary: Accept-Encoding,导致缺失关键维度 -
gzip_vary 被禁用或未继承:确认配置在
http或server块,且未在location中被设为off;子块中未显式关闭即继承上级值
HTTP/2 下的特别注意事项
HTTP/2 本身不发送 Accept-Encoding 请求头(因 HPACK 已高效压缩头部),但客户端仍会发该头,且语义不变。Nginx 不因协议升级而跳过 Vary 逻辑 —— 只要后端返回未压缩内容、Nginx 又启用了 gzip,就仍需 gzip_vary on,否则压缩版与未压缩版可能被同一缓存条目错误复用。


















