HTTP 缓存
HTTP 缓存复用已有响应,减少传输与源站计算。本文负责缓存存储、新鲜度和条件验证。
1. 面试核心
先记住这几条,再读正文- 新鲜度。 新鲜响应可直接复用,过期响应按规则验证或重新获取。
- 缓存指令。 无字段参数的 no-cache 要求复用前验证,no-store 禁止存储。卡 · 面试核心
- 条件验证。 GET 的 If-None-Match 匹配当前 ETag 时可返回 304。卡 · 条件请求
- 共享缓存。 s-maxage 设置共享缓存寿命,Vary 扩展响应匹配条件。卡 · 共享缓存与 Vary
2. 存储与新鲜度
Cache-Control: public, max-age=60
ETag: "version-7"
允许缓存的响应可在新鲜期内复用。缓存结合 Date、Age 和驻留时间计算响应年龄。转发响应不会重新获得完整的 60 秒。
max-age 优先于 Expires。共享缓存采用 s-maxage 时,它又优先于 max-age。缺少显式寿命时,缓存可按规范使用启发式新鲜度。未设置 Cache-Control 的响应也有机会被缓存。
private 限定私有缓存使用。public 允许共享存储,但个人数据仍需正确隔离。携带 Authorization 的请求另受共享缓存规则约束。
3. 条件请求
GET /catalog HTTP/1.1
If-None-Match: "version-7"
ETag 标识一个表示版本。GET 的验证条件匹配时,服务器可返回 304。缓存保留原响应体,并更新响应元数据。版本变化时,服务器返回新的表示。
Last-Modified 配合 If-Modified-Since 按修改时间验证。HTTP 日期精度为秒。ETag 可表达时间戳无法区分的版本变化。
两组条件同时出现时,If-None-Match 优先。If-None-Match 使用弱比较。弱 ETag 表示语义等价,强 ETag 还要求表示数据一致。范围请求的 If-Range 需要强验证器。
304 仍产生网络往返,只省去响应体传输。它依赖缓存中已有的对应表示。
4. 共享缓存与 Vary
Cache-Control: public, max-age=60, s-maxage=300
Vary: Accept-Encoding
这里私有缓存的显式寿命为 60 秒。共享缓存的显式寿命为 300 秒。Vary 要求缓存匹配请求的 Accept-Encoding。gzip 与其他编码的响应因此分别匹配。
URL 是缓存键的重要部分。Vary 可补充语言、编码等请求头维度。用户私有响应应使用 private 等合适策略。把用户身份遗漏在共享规则之外会导致数据串用。
5. 使用边界
no-cache 允许存储,但复用前要验证。这里讨论无字段参数的指令。no-store 要求不存储本次请求或响应。历史副本失效仍需独立处理。
must-revalidate 要求过期后成功验证才能复用。源站失联时,缓存应返回错误,例如 504。
6 · 面试题卡片
本页题目与参考回答
6.1 no-cache、no-store 和 304 分别表示什么?
考察重点:缓存存储、新鲜度与条件验证三个不同判断。
参考回答
no-cache 允许存储,但复用前必须验证。
no-store 禁止存储本次请求或响应。这里的 no-cache 没有字段参数。GET 验证当前表示未变时可收到 304。客户端复用旧响应体,仍有一次网络往返。
6.2 ETag 和 Last-Modified 同时用于验证时,哪个优先?
考察重点:条件请求优先级与验证器强弱。
相关内容:条件请求。
参考回答
If-None-Match 优先,服务器忽略 If-Modified-Since。
GET 中 ETag 匹配可返回 304。时间验证受秒级精度约束,ETag 则标识表示版本。If-None-Match 允许弱比较,If-Range 要求强验证器。
6.3 浏览器与 CDN 怎样使用不同缓存寿命并区分压缩响应?
考察重点:私有与共享缓存、响应变体。
相关内容:共享缓存与 Vary。
参考回答
用 max-age 设置基本缓存寿命,再用 s-maxage 为 CDN 等共享缓存覆盖该值。
Vary: Accept-Encoding 让缓存按请求的编码能力匹配响应。共享缓存还需遵守 private 和鉴权规则,避免把用户私有响应用于其他请求。