应避免直接使用 vary: user-agent,而需通过 nginx map 归类设备类型为 mobile/tablet/desktop,仅在内容真实差异时添加 vary "x-device-type" 并同步注入该头,同时配置 cdn 支持自定义 vary 字段,并确保 proxy_cache_key 包含 $device_type 以保持缓存键一致。

直接用 Vary: User-Agent 会让缓存系统把每个 UA 当作独立版本,导致缓存键爆炸、命中率归零。真正有效的做法是:先归类设备类型,再声明差异,最后让 CDN 正确识别这个声明。
用 map 归类设备,生成稳定标识
Nginx 无法实时解析 UA,但可以用 map 指令做静态匹配,把千变万化的 UA 映射为有限、可预测的值。推荐放在 http 块中:
-
~*[Mm]obi|[Aa]ndroid|[Ii]phone|[Ii]pad→mobile -
~*[Tt]ablet→tablet - 其余默认 →
desktop
这样得到的 $device_type 是稳定字符串,适合参与缓存决策,不会引发缓存分裂。
只在内容真有差异时才加 Vary
Vary 不是设备检测开关,而是内容差异的“说明书”。只有当 Nginx 或后端确实返回了不同响应时,才需要声明:
- 页面完全响应式,JS/CSS/HTML 都一样 → 不加
Vary - 根据
$device_type注入了不同 JS bundle、meta 标签或跳转逻辑 → 加add_header Vary "X-Device-Type"; - 同时适配设备和图片格式(如 WebP)→
add_header Vary "X-Device-Type, Accept";
务必同步注入标识头:add_header X-Device-Type $device_type;,否则 Vary 字段无意义。
让 CDN 正确使用自定义 Vary 字段
主流 CDN 默认只认 User-AgentAccept-Encoding 等标准字段。若用了 X-Device-Type,必须手动配置:
- 在 CDN 控制台开启「自定义 Vary 字段」支持
- 将
X-Device-Type加入「Vary 白名单」或「缓存键参数」列表 - 确认回源请求携带原始
User-Agent(否则 Nginx 无法生成$device_type)
否则 Nginx 设置的 Vary 在 CDN 层会被忽略,等同于没设。
配合缓存键保持一致
Vary 声明和缓存键必须严格对应,否则行为不可控。例如在 proxy_cache_key 中加入设备类型:
proxy_cache_key "$scheme$request_method$host$request_uri$device_type";- 若还涉及语言或压缩,也需一并纳入:
$http_accept_language$http_accept_encoding$device_type
不一致会导致 CDN 认为该缓存可复用,而实际返回了错版内容——这就是内容混淆的根源。










