用户登录

技术文章

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

HTTP 缓存与 CDN 加速:先确定缓存键与新鲜度,再谈命中率

一句话回答

CDN 只是执行 HTTP 共享缓存语义的一层,落地顺序应是先划分可共享/私有/不缓存三类路径,再写 Cache-Control 与 ETag,然后确认缓存键(Vary)是否收敛,最后用版本化 URL 而不是主动清除来保证更新可控。带用户态的响应若标成 public 并进入共享缓存会串号;具体厂商默认值与清除生效时间需查官方文档。

核心要点 TL;DR
  • CDN 不创造新语义,它执行的是 Cache-Control 的共享缓存规则;先定 s-maxage 与 public/
  • no-store 与 no-cache 不等价:前者禁止存储,后者允许存储但每次使用前必须校验。
  • 静态资源用内容哈希做版本化 URL 比依赖主动清除更可控,代价是历史文件需要清理策略。

CDN 加速看起来是“多部署几个节点”,实际执行的是 HTTP 缓存语义:边缘节点按响应头判断一份响应能否被共享缓存、存多久、过期后如何校验。因此顺序应当是先改响应头、再谈节点与命中率。下面只写能由 HTTP 缓存规范推导的部分;具体 CDN 厂商的默认 TTL、清除生效时间、响应头命名,本次没有可核验材料,需以对应厂商官方文档为准。

一、四个决定缓存的信号#

  • Cache-Control:max-age 面向浏览器,s-maxage 面向共享缓存(CDN)。public 与 private 决定能否进共享缓存。
  • no-store 与 no-cache 不等价:no-store 不允许存储;no-cache 允许存储,但每次使用前必须回源校验。混用会让“不想缓存”变成“每次都多一次往返”。
  • 验证器(ETag / Last-Modified):配合条件请求返回 304,省的是传输体积,不是往返次数。
  • Vary:声明哪些请求头参与生成缓存键。加得越多,键越分散,命中率越低。

二、更新策略:优先改 URL,而不是依赖清除#

  • 静态资源带内容哈希,例如 /app.3f9a1c.js,配长 max-age 加 immutable;内容变了 URL 就变,不涉及清除。
  • HTML 这类入口文件用短 max-age 或 no-cache 加 ETag,保证能及时看到新引用。
  • 主动清除依赖厂商接口与生效时间,能改 URL 时不必把它当主路径,只作为兜底。
  • 代价:版本化 URL 会留下历史文件,需要单独的清理策略,否则存储与发布产物会持续增长。

三、两个高频边界#

带用户态的响应进了共享缓存

响应如果由 Cookie 或 Authorization 派生,却被标成 public 并被边缘缓存,就会出现不同用户拿到同一份内容。判断依据很直接:响应里是否有 Set-Cookie,内容是否随身份变化。部分 CDN 有“含 Set-Cookie 即不缓存”的默认行为,但默认值因厂商而异,需核实。

缓存键被 Vary 打散

Vary: User-Agent、Vary: Cookie 这类写法会让每个请求都成为新的键,命中率接近零,而表面上配置“正确”。收敛缓存键通常比增加节点更有效。

四、示例:一组自洽的响应头#

下面为 Nginx 通用指令写法,未实际执行,也未做压测,仅用于说明配置形状。

location /static/ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

location = /index.html {
    add_header Cache-Control "no-cache";
    etag on;
}

注意 Nginx 的 add_header 存在层级继承规则,子层级一旦出现新的 add_header,父级配置不会自动叠加,实际项目需整体检查响应头。

五、上线前的核对顺序#

  1. 把路径分三类:可共享、私有、不缓存,逐条写下判断依据。
  2. 对可共享路径补 s-maxage 与 ETag,确认二次请求返回 304。
  3. 确认缓存键:URL 加上真正影响内容的请求头,不多不少。
  4. 观测命中率、回源量与 Age;具体统计入口与响应头名称随厂商不同,待核实。
  5. 把发布流程固化为“改哈希优先、清除兜底”,并记录清除的失败处理。

缓存配置的难点不在写头,而在划分边界:哪些响应可以被所有人共用,哪些一旦共用就是事故。把这一步写清楚,剩下的通常是取值与观测。

作者:沐小悠

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

更多文章 GET 示例接口

「」标签下的其他文章