用户登录

技术文章

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

HTTP 缓存与 CDN 加速:先分清谁能缓存,再定 TTL 与失效

一句话回答

HTTP 缓存与 CDN 加速的关键,是先判断响应能否进入共享缓存,再用 Cache-Control 区分私有与共享新鲜期,用 ETag 等校验器减少重复传输,并让 Vary 与缓存键保持一致;静态资源优先用文件名哈希失效,动态接口默认不共享缓存再逐条放开。

核心要点 TL;DR
  • 共享缓存会把同一份响应复用给不同用户,个性化响应必须先排除在共享缓存外。
  • no-cache 表示使用前必须校验,不等于不缓存;不存储要用 no-store。
  • 失效优先用文件名带内容哈希,主动 purge 的生效时间取决于服务商,需核实。

HTTP 缓存与 CDN 加速,关键不在把 TTL 调大,而在先回答一个问题:这个响应能不能被共享缓存保存并复用给其他用户?分类错了,后面调什么参数都会出问题。字段语义以 IETF 的 HTTP 缓存标准 RFC 9111 为准;本次未联网核验各 CDN 厂商的具体实现,涉及厂商差异的部分在文中单独标出。

先分清缓存所在的位置#

  • 浏览器私有缓存:只服务单个用户,保存个性化响应通常安全。
  • CDN 边缘共享缓存:一份副本可能返回给多个用户,只要响应因人而异,就必须阻止它进入共享缓存。
  • 源站与回源链路:回源频率由边缘缓存的新鲜期决定,源站压力问题往往要在这一层解决。

Cache-Control 的几个决定性字段#

字段作用常见误用
max-age响应新鲜期,私有与共享缓存都适用给带登录态的接口设长新鲜期
s-maxage只对共享缓存生效,覆盖 max-age以为设了它就同时控制浏览器
private / public声明是否允许共享缓存存储不写,交给中间层默认策略
no-cache可以存储,但每次使用前必须向源站校验当成“完全不缓存”
no-store不允许存储与 no-cache 混用
stale-while-revalidate过期后先返回旧副本、后台再校验默认所有 CDN 都支持(需核实)

实践上,公开静态资源用较长的 max-age;接口按“能否共享”二分:能共享的写 public, s-maxage=…,不能共享的直接 private, no-store,不要留空让中间层替你决定。

校验器:ETag 与 Last-Modified#

新鲜期过后,缓存可以带上 If-None-Match 或 If-Modified-Since 回源校验,源站返回 304 即可省掉响应体。ETag 需要与内容真实对应:若源站按多台机器各自生成、或随响应变化而抖动,校验就退化为每次全量传输。压缩、转码链路是否会改写 ETag,取决于具体实现,需按实际链路核对。

Vary 与缓存键必须一致#

Vary 声明“哪些请求头会影响响应”,常见值是 Accept-Encoding、Accept-Language。它必须同时体现在缓存键里,否则会出现缓存命中错版本的问题;Vary: * 实际上会让响应难以被复用。CDN 的默认缓存键通常由主机名、路径和查询串组成,但组成方式与是否忽略指定参数由厂商配置决定,待核实。查询参数顺序不同会形成不同缓存键,接口层应做参数规范化。

失效的两条路径#

推荐静态资源走“文件名带内容哈希 + 长新鲜期”,发布即换 URL,不依赖主动失效。主动 purge 适合配置、文案这类无法改名的资源,但其生效时间与是否同步返回结果因厂商而异,不能假设调用成功即全网生效。回滚时要注意:旧文件名若已被清理,回滚需重新发布而非仅切回引用。

示意配置(未执行示例)#

以下片段仅示意头部写法,未在真实环境执行,端口、路径与中间件版本需按项目调整。

// 示意:Node.js / Express 风格,未执行
app.get('/api/public-config', (req, res) => {
  res.set('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=30');
  res.json(config);
});

app.get('/api/me', (req, res) => {
  res.set('Cache-Control', 'private, no-store');
  res.json(profile);
});
# 示意:Nginx 静态资源,未执行
location ~* \.(?:js|css|woff2|png)$ {
  add_header Cache-Control "public, max-age=31536000, immutable";
}

上线前核对清单#

  1. 逐个接口标注“可共享 / 不可共享”,并检查响应头是否与该判断一致。
  2. 确认 no-cache 与 no-store 没有被混用。
  3. 核对 Vary 是否进入缓存键,压缩与多语言是否命中正确版本。
  4. 核对缓存键是否包含全部影响响应的查询参数,并做顺序规范化。
  5. 确认主动 purge 的生效范围与延迟,准备好不依赖 purge 的发布方式。
  6. 用带身份的请求与匿名请求各验证一次,确认不会互相串用缓存。

边界与待核实项#

各 CDN 对 s-maxage、stale-while-revalidate、immutable 的支持程度,以及 purge 的生效时间、默认缓存键组成,均需查阅对应厂商文档确认,本次材料不足以给出结论。涉及登录态、灰度分流、AB 实验的接口,建议默认按不可共享处理,再逐条放开并复核,而不是先全量开启缓存再排查。

作者:沐小悠

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

更多文章 GET 示例接口

「」标签下的其他文章