应基于归类后的稳定设备类型(如mobile/tablet/desktop)设置Vary,而非直接使用碎片化的User-Agent;通过Nginx map模块生成可预测变量,并仅在真实返回差异化内容时添加对应Vary头,配合CDN正确识别与缓存。

直接用 User-Agent 做 Vary 会严重降低缓存命中率——UA 字符串太碎,CDN 里同一页面可能存几十个变体。真正有效的做法是:先在 Nginx 内部归类设备类型,再基于稳定枚举值设置 Vary,确保后端返回差异内容时,缓存系统能正确区分。
用 map 模块生成稳定设备标识
不直接依赖千变万化的 UA,而是用 map 把请求归为有限几类(如 mobile/tablet/desktop),这个变量才适合参与缓存键和 Vary 决策:
- 在
http块中定义:
map $http_user_agent $device_type {
default desktop;
~*[Tt]ablet tablet;
~*[Mm]obi|[Aa]ndroid|[Ii]phone|[Ii]pad mobile;
}
- 同样可为 WebP 支持建映射:
map $http_accept $webp_support { default "0"; ~*webp "1"; } - 这些变量值固定、可预测,不会导致缓存爆炸
只在真实返回差异化内容时加 Vary
Vary 不是越多越好,必须和实际响应逻辑严格对应。加了但没用,反而让缓存系统多存一份无效副本:
- HTML 页面做了服务端移动适配 → 响应头加
Vary: X-Device-Type(你自定义的头),并在add_header中注入该头 - 图片资源根据
Accept返回 WebP/JPEG → 加Vary: Accept - 同时适配设备 + 图片格式 →
Vary: X-Device-Type, Accept(逗号分隔,注意空格) - 关键点:Nginx 必须在代理到 CDN 前完成这些头的写入,否则 CDN 看不到
配合 CDN 正确识别并生效
很多 CDN 默认忽略或弱化 Vary,尤其对自定义头(如 X-Device-Type)支持不一:
- 优先使用 CDN 提供的标准设备头(如 Cloudflare 的
CF-Device-Type),它已预设好缓存策略 - 若必须用自定义头,确认 CDN 控制台是否开启 “尊重 Vary 头” 或类似开关
- 用
curl验证:发两个不同 UA 的请求(一个手机、一个桌面),检查响应中Vary是否一致、缓存状态是否分离(如X-Cache: HIT出现在各自请求中,而非混用)
避免常见陷阱
几个高频出错点,直接影响命中率:
-
不要漏掉
gzip_vary on:启用 gzip 时,它自动加Vary: Accept-Encoding,但仅对实际压缩的响应生效;未压缩请求需靠add_header Vary Accept-Encoding补全,否则 CDN 可能乱发压缩内容 -
不要在静态资源上滥用
Vary: User-Agent:JS/CSS/PNG 等通常无需按设备区分,加了反而让 CDN 缓存碎片化 -
确保后端真实返回差异内容:如果 PHP/Node 后端没根据
$device_type切模板,却加了Vary: X-Device-Type,纯属浪费缓存空间


















