HTTP 缓存与 CDN 加速实践:缓存键、校验与回源责任怎么划
缓存与 CDN 的收益来自减少回源,但正确性取决于三件事:响应能否被共享缓存存储、缓存键是否覆盖影响内容的所有请求维度、过期后由谁校验或失效。本文按 RFC 9111 的通用语义解释 max-age 与 s-maxage 的作用范围、no-cache 与 no-store 的区别、Vary 与 CDN 缓存键不一致的风险,以及 ETag 条件请求在其中的位置;具体 CDN 厂商的默认 TTL、清除时效与命中判定字段本次无资料,标为待核实。
要让 HTTP 缓存与 CDN 真正加速,先要回答三个问题,而不是先调 TTL:这个响应允许被谁存储?哪些请求算“同一个资源”?过期之后由谁负责校验或失效?这三件事没定清楚,加缓存只是把错误的内容更快地发给更多人。本文只讲协议层面的通用口径;具体 CDN 产品的默认 TTL、清除生效时间、命中判定字段,本次没有可核验资料,均标为待核实。
一、先分清三种缓存归属#
HTTP 缓存(HTTP Caching,语义见 IETF 的 RFC 9111)把缓存分为私有缓存与共享缓存。浏览器缓存属于私有,CDN 边缘节点属于共享。同一个响应头在不同归属下效果不同:
private:只允许私有缓存存储,共享缓存不应保存。s-maxage:只对共享缓存生效,并优先于max-age;它同时带有要求共享缓存过期后必须校验的语义。no-store:任何缓存都不应存储。no-cache:允许存储,但每次使用前必须向源站校验。常见误读是把它当成“不缓存”,实际是“存但必校验”。
把 no-cache 写成 no-store,命中率会被自己砍掉;反过来把该私有的响应写成 max-age,共享缓存就会替你把个性化内容发给别人。
二、缓存键:Vary 与 CDN 键配置必须对齐#
Vary 声明哪些请求头参与“选哪个缓存条目”。常见维度是 Accept-Encoding(压缩格式)、Accept-Language,以及业务自定义的地区、设备标记。少写一个维度,就会出现“同一 URL 返回了另一种变体”。
两个容易错的点:
- Authorization:带该请求头的请求,共享缓存默认不得存储其响应,除非响应显式声明
public、s-maxage或must-revalidate。这是协议层面的限制,不是厂商策略。 - Set-Cookie:协议并未禁止缓存含该头的响应,但只要被共享缓存复用,会话标识就可能落到别的用户手里。实践上应配
private或no-store,而不是依赖边缘节点“应该会跳过”。
还要注意:Vary 是源站表达,CDN 的缓存键是边缘侧配置,两者是两套机制。若边缘键只看 URL 而源站按 Vary 分发变体,就会出现源站认为不同、边缘认为相同的错配。各家键配置项的粒度与上限需查对应文档,此处待核实。
三、新鲜期、校验与失效#
| 指令 | 作用对象 | 语义要点 |
|---|---|---|
max-age | 私有与共享缓存 | 相对响应生成时间的新鲜期 |
s-maxage | 仅共享缓存 | 覆盖 max-age,过期后须校验 |
must-revalidate | 所有缓存 | 过期后不得使用陈旧副本 |
stale-while-revalidate | 支持者 | 来自 RFC 5861,非核心规范;先给旧值、后台刷新,需两端支持 |
过期之后走条件请求:源站用 ETag / If-None-Match 或 Last-Modified / If-Modified-Since 判断是否变化,未变则返回 304,不重传正文。ETag 的强弱语义会影响范围请求与内容合并的判断,改动响应体生成逻辑时要同步考虑 ETag 是否还成立。
四、CDN 侧的四个判断条件#
- 可缓存内容占比决定命中率上限。登录态接口、实时库存这类响应通常不该进共享缓存,调 TTL 也救不回来。
- 回源成本不只在带宽:压缩是否在边缘完成、连接是否复用、TLS 在哪一层终止,都会影响缓存能否读到明文请求头来做键决策。
- 清除(purge)是兜底而非常规手段。如果发布流程依赖“发完再清缓存”,说明 TTL 与文件名版本化策略没设计好。
- 观测要看命中而非只看平均耗时。标准字段是
Age(响应在缓存中已存在的估算时长);命中标记多为厂商自定义响应头,字段名与含义待核实。
五、核对示例(未执行)#
下面只是查看响应头的命令骨架,使用占位域名 example.com,本文未实际执行,因此不给出任何输出结果。
curl -sI https://example.com/static/app.js
拿到响应后逐项核对:Cache-Control 是否区分了私有与共享、是否误用 no-store;Vary 是否覆盖了实际影响内容的请求头;ETag 是否存在且与内容一致;Age 是否说明请求确实命中了中间缓存。
六、边界#
本文没有涉及具体 CDN 厂商的配置面板、边缘计算、动态加速与 ESI 等能力,这些必须以厂商文档为准。最终判据不是命中率数字,而是“错误内容被复用的代价”:可公开的静态资源可以给长 TTL 加文件名指纹;涉及身份与权限的响应,宁可少缓存,也不要把判断权交给默认配置。