核心是统一声明Vary: Accept-Encoding:仅gzip_vary on不够,因它只在压缩时添加该头;必须配合gzip on和add_header Vary Accept-Encoding always,确保所有响应(含未压缩)都携带该头,避免缓存混淆。

在 Nginx 中为 Gzip 响应正确添加 Vary 字段,核心不是“选择加不加”,而是确保所有响应(无论是否压缩)都统一声明 Vary: Accept-Encoding,从而让浏览器、CDN 和反向代理能准确区分压缩与未压缩两个缓存变体。
为什么不能只靠 gzip_vary on
gzip_vary on 是条件性行为:仅当 Nginx 实际执行了 gzip 压缩时,才自动添加 Vary: Accept-Encoding;如果请求没带 Accept-Encoding: gzip(比如某些监控探针、iOS WebView、安全扫描器或禁用压缩的客户端),Nginx 不压缩,也不加该头。此时缓存系统会把这份未压缩响应当作“通用版本”存储,后续带 gzip 的请求可能被错误返回明文内容,导致 JS 解析失败、CSS 加载异常或页面空白。
正确配置三要素
必须同时满足以下三点,缺一不可:
-
启用压缩功能:
gzip on;(写在 http/server/location 块中) -
允许 Nginx 智能补全:
gzip_vary on;(它会在压缩响应中自动加 Vary,作为基础保障) -
强制统一声明:
add_header Vary Accept-Encoding always;(覆盖所有状态码,确保未压缩响应也带该头)
关键细节提醒
避免常见陷阱:
- 不要用
proxy_hide_header Vary—— 这会主动移除 Vary,彻底破坏缓存隔离 - 若使用
proxy_cache,必须让proxy_cache_key包含$http_accept_encoding,例如:proxy_cache_key "$scheme$request_method$host$request_uri$http_accept_encoding"; - 检查是否误启
proxy_ignore_headers Vary;—— 它会让 Nginx 忽略后端返回的 Vary,导致缓存行为失控 -
add_header要写在gzip on之后,且不能被其他指令覆盖
验证是否生效
用 curl 检查两类典型请求:
-
curl -I -H "Accept-Encoding: gzip" https://yoursite.com/app.js→ 应含Content-Encoding: gzip和Vary: Accept-Encoding -
curl -I -H "Accept-Encoding: identity" https://yoursite.com/app.js→ 应无Content-Encoding,但仍含Vary: Accept-Encoding - 两次请求的缓存标识(如
X-Cache)应为不同条目,而非共用一个


















