Vary头需精准反映实际影响响应的请求头,避免漏加导致缓存混用或乱加引发碎片化;应基于后端真实逻辑判断是否Vary,如Origin、User-Agent等,并用map归一化不稳定头(如UA),确保Vary与缓存键协同一致。

核心在于让 Vary 头精准反映实际影响响应内容的请求头,既不能漏加(导致缓存混用),也不能乱加(导致缓存碎片化)。关键不是“加 Vary”,而是“加对 Vary”。
明确哪些请求头真正在影响响应内容
Vary 告诉浏览器和中间缓存:“如果这个请求头变了,响应内容可能就不同,得单独存一份”。所以第一步是确认后端是否真的根据某个头返回了不同内容:
- 如果后端对所有 Origin 都返回完全一样的数据(比如始终用
Access-Control-Allow-Origin: *),那就不该加Vary: Origin;加了反而让每个 Origin 都建独立缓存,浪费空间、降低命中率 - 如果后端对 User-Agent 返回了不同 HTML(如 PC 版 vs 移动版),那才需要
Vary: User-Agent;但如果只是返回同一份 HTML,只是前端 JS 再适配,就不该加 - 同理,
Accept、Accept-Language等也需按真实逻辑判断——多数 API 不区分语言,就不该 Vary
用 map 归类不稳定请求头,避免缓存爆炸
直接 Vary User-Agent 是危险操作:UA 字符串成千上万,缓存会迅速分裂成海量无效副本。正确做法是在 Nginx 内部做归一化:
- 用
map指令把 UA 映射为有限枚举值,例如:map $http_user_agent $device_type {<br> ~*android|iphone|ipad "mobile";<br> ~*tablet|kindle "tablet";<br> default "desktop";<br>} - 再用这个稳定变量参与缓存键和 Vary:
proxy_cache_key "$scheme$request_method$host$request_uri$http_accept_language$device_type";<br>add_header Vary "Accept-Language, X-Device-Type";
- 确保自定义头
X-Device-Type在代理前已注入:proxy_set_header X-Device-Type $device_type;
配合缓存键与响应头保持一致
Vary 和缓存键必须协同工作,否则缓存行为不可控:
- 若决定 Vary
Origin,缓存键里就必须包含$http_origin(或用 map 将空 Origin 统一为"null",避免有/无 Origin 分裂) - 若后端已返回 Vary 头,Nginx 默认会透传;但为防遗漏,建议显式设置:
add_header Vary "Origin" always;(always确保即使后端没发也补上) - 检查是否误用了
proxy_ignore_headers,它可能直接丢弃了后端返回的 Vary,导致缓存失效
验证是否真正生效
别只看响应头,要观察缓存行为本身:
- 用 curl 模拟不同条件请求:
curl -I -H "Origin: https://a.com" https://api.example.com/data<br>curl -I -H "Origin: https://b.com" https://api.example.com/data
- 重点看两点:
— 响应头中是否都含Vary: Origin
— 两次请求的X-Cache(或你自定义的缓存标识头)是否一个 HIT 一个 MISS(说明缓存键已隔离)、或都 HIT(说明 Vary 正确且缓存复用正常) - 如果都 MISS,问题不在 Vary,而在缓存配置未启用、路径不匹配或 proxy_cache_path 未正确定义











