单靠 gzip_vary on 不够,因其仅在实际压缩时添加 vary: accept-encoding,未压缩响应缺失该头会导致缓存混淆;必须同时启用 gzip on、gzip_vary on 和 add_header vary accept-encoding,并确保 gzip_types、gzip_min_length 及 proxy_cache_key 含 $http_accept_encoding。

要让 Nginx 正确通过 Vary: Accept-Encoding 告知客户端和缓存系统“响应内容会因压缩能力而不同”,不能只依赖 gzip_vary on,必须配合显式声明,确保所有响应(无论是否压缩)都携带该头。
为什么单靠 gzip_vary on 不够
Nginx 的 gzip_vary on 是条件性行为:仅当实际执行了 gzip 压缩时,才自动添加 Vary: Accept-Encoding;如果请求未带 Accept-Encoding: gzip(例如旧爬虫、监控探针、禁用压缩的浏览器),Nginx 不压缩,也不加这个头。此时缓存系统会把未压缩响应当作“通用版本”存储,后续带 gzip 请求可能被错误返回明文,导致 JS 报 Unexpected token 或页面空白。
正确配置方式(三要素缺一不可)
在 http、server 或 location 块中同时启用:
-
gzip on;—— 启用压缩功能 -
gzip_vary on;—— 允许 Nginx 在压缩时自动加 Vary 头 -
add_header Vary Accept-Encoding;—— 强制所有响应(含未压缩)都带上该头
注意:add_header 必须写在 gzip on 之后,且不能被 proxy_hide_header Vary 覆盖,否则关键标识会被主动移除。
配套关键配置不能漏
仅加 Vary 头还不够,还需同步保障压缩覆盖与缓存隔离:
-
gzip_types至少包含:text/css application/javascript application/json text/xml,避免漏压核心资源 -
gzip_min_length 1024;防止小文件压缩反而增大体积 - 若使用
proxy_cache,确认proxy_cache_key包含$http_accept_encoding,否则缓存无法按编码区分
验证是否真正生效
用 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→ 应返回Vary: Accept-Encoding,但无Content-Encoding
两次响应在 CDN 或代理中必须命中不同缓存条目(如 X-Cache: HIT 对应不同 key),否则说明 Vary 未起作用。











