开启 gzip_vary on 并配合 add_header Vary "Accept-Encoding" always 和 Cache-Control: public, immutable, max-age=31536000,可精准区分压缩/未压缩响应缓存,提升 CDN 命中率并确保长期稳定缓存。

直接配置 gzip_vary on 并配合合理的 Cache-Control,就能解决因 Vary: Accept-Encoding 导致的 CDN 缓存命中率下降问题。关键不在“加不加”,而在“加得对不对”——既要让压缩响应被正确区分缓存,又不能破坏共享缓存的复用逻辑。
确保 gzip_vary 开启且生效
Nginx 自带的 gzip_vary on 是最稳妥的方式,它只在实际执行了 gzip 压缩时才自动添加 Vary: Accept-Encoding 响应头。这比手动 add_header Vary Accept-Encoding 更精准,避免给未压缩响应也加头,造成 CDN 误判。
- 必须开启
gzip on,否则gzip_vary不起作用 -
gzip_types要覆盖常用静态资源类型(如application/javascript、text/css、image/svg+xml) - 确认没有禁用 gzip 的规则(例如
gzip_disable "msie6"在现代环境可移除)
统一 Vary 头存在性,避免条件缺失
gzip_vary on 只对触发压缩的响应加头。但若某次请求不带 Accept-Encoding: gzip,Nginx 不压缩、也不加 Vary,CDN 就可能把该未压缩响应当作“通用版本”缓存并错误返回给 gzip 客户端。
所以要在同一 location 中补上兜底配置:
-
add_header Vary "Accept-Encoding" always;(always参数确保无论是否压缩都生效) - 或更简洁地:在启用 gzip 的前提下,直接写
add_header Vary "Accept-Encoding";,配合gzip_vary on形成双重保障
搭配 immutable + max-age 实现长期稳定缓存
光有 Vary 不够,还得让 CDN 和浏览器愿意长期存这个“按编码分版本”的缓存。
- 对带哈希指纹的静态资源(如
main.a1b2c3.js),设Cache-Control: public, immutable, max-age=31536000 -
public允许 CDN 和中间代理缓存 -
immutable告诉浏览器:只要没过期,就别发If-None-Match等验证请求,省去一次往返 - 注意:
immutable仅适用于内容永不变更的资源,动态页或无哈希文件不要用
验证 CDN 是否真正尊重 Vary
很多缓存问题出在 CDN 层忽略 Vary 头。用 curl 快速验证:
- 请求带
Accept-Encoding: gzip:curl -H "Accept-Encoding: gzip" -I https://example.com/main.js,检查响应是否有Vary: Accept-Encoding和Content-Encoding: gzip - 请求不带压缩头:
curl -H "Accept-Encoding:" -I https://example.com/main.js,检查是否返回未压缩内容,且Vary头仍存在 - 两次请求的
ETag或Last-Modified应不同,说明 CDN 确实分开了缓存
如果两次响应完全一致,说明 CDN 没按 Vary 区分,需联系厂商确认是否支持或开启相关功能。











