HTTP 缓存与 CDN 加速实践:从可缓存性判定到边缘验证
缓存与 CDN 加速的先后顺序是:先判定响应能否被复用、由谁复用、复用多久、何时必须校验,再讨论边缘节点部署。本文把这条链路拆成可判定的字段与验证步骤,并说明哪些结论需要实测、哪些属于规范定义而非厂商承诺。
缓存和 CDN 加速要解决的问题,首先要分清“这段响应能不能被重复使用”,其次才是“复用得多快”。如果缓存键、新鲜期和校验条件没有写清,边缘节点只会把错误的响应更快地发给更多人。需要先说明:本次写作没有可用的正文素材,因此下文只讨论 HTTP 缓存规范层面可判定的概念与验证方法,不引用任何 CDN 厂商的具体行为、版本差异或性能数字;凡涉及具体产品表现的,一律标为待核实。
一、把“复用条件”拆成四个问题#
按 HTTP 缓存规范(RFC 9111)的定义,一个响应是否被复用,取决于四件事。本文未附规范原文链接,具体条款请以 RFC 9111 为准。
- 谁可以存:
public表示共享缓存(如 CDN)也可保存;private表示只允许浏览器这类私有缓存保存;no-store表示不得存储。 - 存多久:
max-age面向私有缓存,s-maxage面向共享缓存。两者同时出现时,共享缓存应优先采用s-maxage。 - 用前是否校验:
no-cache不是“不缓存”,而是“每次使用前必须先向源站校验”;must-revalidate约束的是过期之后的复用行为。校验通常靠ETag与If-None-Match完成,命中时源站返回304。 - 不同请求能否共用同一份:
Vary声明哪些请求头参与缓存键,例如按Accept-Encoding区分压缩与非压缩版本。缺少Vary时,内容协商就可能把一份响应错发给另一类客户端。
二、CDN 是共享缓存,指令要分开写#
CDN 节点属于共享缓存,因此只写 max-age 并不能表达“边缘可以缓存多久”。把 s-maxage 单独写出来,才能让浏览器与边缘各自按不同时长工作。带 Authorization 或 Cookie 的响应在规范下的默认可共享性受限,是否放行取决于 public 等指令与 CDN 自身配置;具体实现差异需要以所用 CDN 文档为准,本文无法核实。
三、可执行的判定顺序#
- 先给资源分类:静态不变资源、按版本命名可长期缓存的资源、频繁变化但可短时复用的接口响应、绝不能存储的响应。
- 为每一类写下
Cache-Control与是否需要ETag,再决定是否加Vary。 - 检查缓存键是否包含所有影响响应内容的维度(路径、查询参数、参与协商的请求头)。
- 在响应日志中记录缓存命中状态与
Age等字段,确认边缘确实按预期复用。具体头名与日志字段因 CDN 而异,待核实。 - 修改缓存策略后,用同一组请求复测,比较命中与回源的比例变化,而不是只看单次响应。
四、响应头骨架(示意,未执行)#
下面的组合仅用于说明字段分工,未在任何服务器或 CDN 上执行,数值也不是推荐值,需按资源实际更新频率确定。
Cache-Control: public, max-age=60, s-maxage=600, must-revalidate
ETag: "v1-example"
Vary: Accept-Encoding
五、验证方式与边界#
可以用响应头观察来验证,下面的命令是演示写法,域名使用 example.com 占位,未实际执行:
curl -sI https://example.com/static/app.js
重点看三处:Cache-Control 是否与设计一致;Age 是否在增长(增长说明命中了共享缓存);带 If-None-Match 重发时是否返回 304。需要提醒的边界是:Vary: * 会使响应实际上无法被复用;把用户相关的响应标成 public 会造成跨用户串号;缓存时长与业务更新频率不一致时,问题往往表现为“改了没生效”,而不是报错。
哪些必须实测#
规范只定义语义,不保证任何 CDN 的实际行为。以下事项只能通过实际请求确认,本文标为待核实:边缘节点的默认缓存时长与忽略规则、查询参数是否参与缓存键、清除缓存的生效时间、以及压缩与协商的具体处理。上线前建议为每类资源保留一条可复现的验证请求,并记录响应头快照作为证据。
本文为 API.PLUS 开发者内容整理,未涉及任何具体接口端点,也未对任何在线服务发起调用。