用户登录

技术文章

外部链接将在新标签页打开。

HTTP 缓存与 CDN 加速实践:缓存键、校验与回源责任怎么划(2026-11-01)

一句话回答

CDN 加速效果主要由三件事决定:缓存键是否只包含决定响应内容的因素、新鲜度与校验策略是否匹配内容变更节奏、源站与 CDN 的回源责任是否边界清晰。缓存键过宽会降低命中率,过窄会造成错配;共享缓存与私有缓存的有效期需要分别看待;回源阶段应由源站保证状态码与缓存头的正确性,而不是假设 CDN 一定会缓存。

多数项目里,CDN 的加速效果并不取决于“有没有接入”,而取决于三点:缓存键是否稳定、新鲜度策略是否与内容变更节奏匹配、回源责任是否只有一处定义。以下讨论的是划分方法与边界条件;具体 CDN 厂商的默认行为、指令支持范围与配额,需以其官方文档和你的实际流量核对,本文未做厂商侧核验。

缓存键:命中率和错配是同一个开关#

缓存键决定“两个请求算不算同一个资源”。它本质上回答一个问题:哪些请求输入会改变响应的字节内容。

  • 键放太宽:把与内容无关的查询参数、跟踪参数、会话标识纳入键,命中率被稀释,缓存层等于白建。
  • 键放太窄:把影响内容的要素排除在外,例如忽略 Accept-Encoding、语言协商或设备类型,就会出现一种编码或语言的内容被发给另一类客户端。

可操作的顺序是先列清单、再定键:把“决定响应内容”的因素逐项写出(路径、必要查询参数、内容协商维度),只有落在清单里的才进键。HTTP 的 Vary 头用于声明内容协商维度,但它同时会细分缓存,维度越多命中率越低,因此应只保留真正影响内容的项。CDN 是否对 Vary 全量支持、是否会在边缘改写键,属于厂商行为,实施前需核实。

新鲜度与校验:分清共享缓存和私有缓存#

缓存是否直接复用响应,取决于是否“新鲜”。Cache-Control 中的 max-age 面向包括浏览器在内的缓存,s-maxage 面向 CDN 这类共享缓存,两者可以给出不同的有效期;private 表示不允许共享缓存存储,no-store 表示不存储。这些是协议层面的语义,具体取值需要结合内容的变更方式决定,而不是套用固定数值。

场景特征更适合的策略方向主要风险
内容有明确发布时刻,可主动刷新较长有效期 + 发布时失效失效操作遗漏会造成长时间旧内容
内容随时可能变,无法预知时刻较短有效期 + 条件请求校验校验请求增多,回源压力上升
含用户态数据private 或不缓存被共享缓存命中导致越权泄露

带校验的路径依赖源站正确实现条件请求:客户端或 CDN 带 If-None-Match,源站比对后返回 304 或新内容。304 不携带正文,但会消耗一次往返,因此“短有效期 + 校验”优化的是带宽与渲染成本,不是往返次数。

回源责任:源站管正确性,CDN 管复用#

边界可以这样切:

  • 源站负责返回正确的状态码、可缓存的响应头与稳定的校验标识(如 ETag)。错误的状态码若被当作可缓存响应保存,后续请求会持续拿到错误。
  • CDN 负责按策略复用响应、处理并发回源合并、执行失效操作。它不能替源站判断内容是否该公开。

常见的责任错位是源站“假设 CDN 一定会缓存”,于是把本该由响应头表达的语义交给平台配置;一旦配置改动或缓存被清除,源站就会被流量直接打到。反过来,源站对带 Set-Cookie 的响应若不声明 private,在共享缓存上是高风险组合。

一个未执行的示例#

下面的响应头仅用于说明字段位置与组合关系,未在任何环境实际执行,也不构成取值建议;实际取值需按内容变更节奏确定。

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=60, s-maxage=300
ETag: "YOUR_ETAG_VALUE"

HTTP/1.1 304 Not Modified
ETag: "YOUR_ETAG_VALUE"

其中 YOUR_ETAG_VALUE 为占位值。

上线前核对#

  1. 列出决定响应内容的因素,与缓存键逐项比对,确认没有多余项和缺项。
  2. 确认含用户态数据的响应不会被共享缓存命中。
  3. 确认源站在条件请求下正确返回 304,且错误响应不被长期缓存。
  4. 确认失效路径可操作、可观测:内容更新后,旧内容还能存活多久。
  5. 就所选 CDN 的默认缓存规则、对 Vary 与各指令的支持范围、清除操作的生效时间,向厂商文档或支持渠道核实。

本文未涉及具体 CDN 产品的当前默认配置与版本特性,这部分信息随产品变化,应在实施前单独核实。

作者:沐小悠

本文约 5 分钟读完 · 关键词:HTTP 缓存、CDN 加速、缓存键、Cache-Control、ETag

更多文章 GET 示例接口

「」标签下的其他文章