HTTP 的 Vary 响应头有什么用?它和缓存命中有什么关系?
简化版
Vary 用来告诉缓存系统:同一个 URL 的响应不仅取决于 URL,还取决于某些请求头。
例如 Vary: Accept-Encoding 表示缓存要按客户端支持的压缩算法区分副本;Vary: Accept-Language 表示要按语言区分副本。
它能保证缓存正确性,但如果维度过多,会降低缓存命中率。
详细版
典型响应:
HTTP/1.1 200 OK
Content-Encoding: br
Vary: Accept-Encoding
这表示对于同一个 URL,支持 br 的客户端和只支持 gzip 的客户端可能拿到不同响应。
缓存代理不能只用 URL 做 key,还要把请求里的 Accept-Encoding 纳入缓存 key。
另一个例子:
Vary: Accept-Language
表示中文用户和英文用户可能拿到不同页面。
Vary 设置不当会出问题:漏设置可能把错误版本发给用户;设置过多可能导致缓存碎片化。
完整版教学
1. 先理解缓存为什么需要 Vary
HTTP 缓存默认很容易让人误解为“URL 相同,响应就相同”。
但真实服务里,同一个 URL 可能根据请求头返回不同内容。
例如:
- 根据
Accept-Encoding返回 gzip 或 br。 - 根据
Accept-Language返回中文或英文。 - 根据
User-Agent返回移动端或桌面端内容。
Vary 就是服务端告诉缓存:这个响应会受到哪些请求头影响。
Vary 的本质是扩展缓存 key,避免不同请求变体互相污染。
2. Vary: Accept-Encoding 最常见
压缩响应经常带:
Vary: Accept-Encoding
Content-Encoding: gzip
因为不同客户端支持的压缩算法不同。
如果 CDN 只按 URL 缓存,可能把 Brotli 响应发给不支持 Brotli 的客户端。
加入 Vary: Accept-Encoding 后,缓存会把不同 Accept-Encoding 的请求分成不同副本。
这能保证内容可正确解码。
3. Vary 会影响缓存命中率
Vary 增加了缓存 key 的维度。
维度越多,缓存越细,命中率可能越低。
| Vary 设置 | 缓存副本数量 | 正确性 | 命中率影响 |
|---|---|---|---|
| 无 Vary | 少 | 可能错误 | 高但危险 |
Accept-Encoding | 适中 | 通常必要 | 可接受 |
Accept-Language | 较多 | 多语言必要 | 有下降 |
User-Agent | 很多 | 易碎片化 | 明显下降 |
* | 不可复用 | 最保守 | 基本无法共享 |
所以 Vary 不是越多越好。
它要精确表达影响响应内容的请求头。
4. 多语言和内容协商场景
假设同一个路径 /docs 对不同语言返回不同内容。
服务端可能响应:
Content-Language: zh-CN
Vary: Accept-Language
这样缓存知道中文请求和英文请求不能共用同一份响应。
如果不加 Vary,英文用户可能看到中文页面。
如果语言维度过细,例如把每种复杂语言优先级组合都作为 key,缓存命中率会很差。
工程上常会把语言归一化成有限几类。
5. User-Agent 维度要谨慎
有些站点会根据 User-Agent 返回不同 HTML。
如果加:
Vary: User-Agent
缓存可能为大量浏览器版本生成大量副本。
这会造成缓存碎片化。
更推荐的方式通常是响应式设计,或者在 CDN 层把设备类型归一化成少数几个维度。
6. Vary 和 Cache-Control 的关系
Cache-Control 决定响应能不能缓存、缓存多久、是否必须再验证。
Vary 决定可缓存响应要按哪些请求头区分版本。
二者配合使用。
例如:
Cache-Control: public, max-age=3600
Vary: Accept-Encoding
这表示响应可被共享缓存保存 3600 秒,但缓存副本要按压缩能力区分。
7. 常见误区与追问
- 误区:Vary 是控制缓存时间的。 缓存时间主要由 Cache-Control 等头控制,Vary 控制缓存变体维度。
- 误区:设置更多 Vary 一定更安全。 维度太多会降低命中率,甚至让缓存几乎不可复用。
- 误区:压缩响应不需要 Vary。 压缩算法不同会影响响应体,通常需要
Vary: Accept-Encoding。 - 追问:Vary: * 表示什么? 表示响应依赖未列明因素,共享缓存通常不能复用该响应。
- 追问:漏掉 Vary 会怎样? 可能把某类客户端的响应错误发给另一类客户端。
- 追问:Vary 和 CDN 有什么关系? CDN 会用它构造缓存 key,影响正确性和命中率。
8. 加强记忆
记住:Cache-Control 管时间,Vary 管版本。
回答 Vary 时一定带上“正确性”和“命中率”这对权衡。