必须同时配置gzip on、gzip_vary on和add_header Vary Accept-Encoding always,因为gzip_vary on仅在实际压缩时添加Vary头,未压缩响应会缺失该头导致缓存混淆,而add_header always确保所有状态码响应均携带Vary,实现缓存键按Accept-Encoding严格隔离。

在 Nginx 中让 Gzip 响应携带 Vary: Accept-Encoding 头,核心是启用 gzip_vary on,但仅靠它还不够——必须确保所有响应(无论是否压缩)都统一声明该变体依据,否则缓存系统会混淆。
为什么不能只依赖 gzip_vary on
gzip_vary on 是条件性行为:Nginx 只在真正执行了 gzip 压缩时才添加 Vary: Accept-Encoding 响应头;而当客户端未声明 Accept-Encoding: gzip(比如旧爬虫、iOS WebView、安全扫描器或禁用压缩的请求),Nginx 不压缩、也不加 Vary 头。此时缓存层可能把这份“未压缩响应”当作通用版本存储,后续带 gzip 请求进来时,反而被返回未压缩内容,导致 JS/CSS 解析失败、页面空白。
正确配置方式(三要素缺一不可)
在 http、server 或 location 块中同时配置以下三项:
-
启用压缩功能:
gzip on; -
允许 Nginx 在压缩时自动加 Vary:
gzip_vary on; -
强制所有响应都带上该头:
add_header Vary Accept-Encoding always;(always确保 304、404 等状态码也生效)
配套要点不能忽略
光有 Vary 头还不够,需同步保障底层一致性:
-
gzip_types必须覆盖关键文本类型,例如:text/css application/javascript application/json text/xml,避免漏压 CSS/JS 导致部分资源无压缩、无 Vary -
gzip_min_length 1024防止小文件压缩开销反超收益 - 若使用
proxy_cache,确认proxy_cache_key包含$http_accept_encoding,否则缓存无法按编码隔离 - 检查是否误用了
proxy_hide_header Vary或proxy_ignore_headers Vary,它们会主动移除关键标识
验证是否真正生效
用 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 或 Nginx 缓存中必须命中不同条目(如 X-Cache 显示 MISS/HIT 分离),否则说明 Vary 未起作用。


















