用户登录

技术文章

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

CDN 加了却没变快:从响应头判断 HTTP 缓存是否真的生效

一句话回答

接入 CDN 后没有变快,通常不是 CDN 没生效,而是请求没有走到缓存,或缓存里没有可复用的副本。可以先读 Cache-Control、Age、ETag 与 Vary 这几个响应头,判断响应由哪一层给出、副本存在了多久、下次能否复用;再按“先看头、再看键、最后看回源”的顺序排查。厂商自定义头、清除与预热的具体行为需查各自文档。

核心要点 TL;DR
  • Age 大于 0 说明响应来自缓存,但不等于缓存策略正确;没有 Age 也不必然代表回源。
  • 带 Authorization 的请求,共享缓存默认不存储,除非响应显式允许;Vary: * 永远匹配失败。
  • 命中率是统计量,缺少统计口径与时间窗时不能直接当作加速效果的证据。

接入 CDN 之后页面没有变快,多数情况不是“CDN 没生效”,而是请求压根没走到缓存,或者走到了缓存但里面没有可复用的副本。判断这件事不必靠感觉:谁回答了这次请求、副本已经存在多久、下次能不能复用,都写在响应头里。本文只讨论通用 HTTP 缓存语义与排障顺序;各家 CDN 的自定义头、清除与预热行为差异较大,需以对应厂商官方文档为准(本次未联网核验)。

先分清这次响应由哪一层给出#

一次请求可能由三个位置响应:浏览器私有缓存、共享缓存(通常就是 CDN 边缘节点)、源站。三者遵循同一套缓存语义(HTTP 缓存规范见 RFC 9111),但可用范围不同:private 只允许浏览器存,s-maxage 只作用于共享缓存并覆盖 max-age。分不清响应来自哪一层,后面调 TTL、调缓存键都是在猜。

三个头足够做第一轮判断#

  • Cache-Control:看有没有 max-age/s-maxage 且大于 0,有没有 no-store、private。
  • Age:表示响应在缓存中已存在的秒数。大于 0 说明这次由缓存给出;但没有 Age 不等于一定回源,部分配置会去掉该头。
  • ETag / Last-Modified:决定副本过期后能否用条件请求换回 304,而不是重传整个响应体。

“配了缓存却没命中”的常见原因#

  • 响应带 Set-Cookie。规范并未因此判定响应不可缓存,但不少 CDN 会被配置成不缓存这类响应,属厂商或配置行为,需核实。
  • 请求带 Authorization。共享缓存默认不得存储这类响应,除非响应显式给出 public、s-maxage 或 must-revalidate 等许可。这是接口响应最容易踩的一条。
  • Vary 维度太细,或写成 Vary: *。后者永远匹配失败,等于放弃缓存。
  • 缓存键混入无用参数。时间戳、随机串、营销参数会让同一份内容被切成许多副本,命中率自然上不去。
  • TTL 过短,或每次回源都改写校验器。副本刚存下就过期,等于没有缓存。

一次最小化核对流程#

  1. 对同一个 CDN 地址连发两次相同请求,比较 Age 是否增长。
  2. 确认响应带可缓存的 Cache-Control,且共享缓存有正向有效期。
  3. 检查是否出现 Set-Cookie、private、Vary: *。
  4. 带上响应里的 ETag 发条件请求,期望返回 304。
  5. 以上都正常但仍然慢,问题可能在 TLS 握手、首字节时间、压缩或回源链路,与缓存无关;这一步需要真实链路数据才能下结论。

示例:读一个响应头#

下面的命令与响应均为示意,example.com 是占位域名,命令未执行,输出不代表任何真实服务。

curl -sSI "https://example.com/api/v1/items?page=1" \
  -H "Accept-Encoding: gzip"

# 示意响应(非真实抓包)
HTTP/1.1 200 OK
Cache-Control: public, max-age=60, s-maxage=600
Age: 421
ETag: "v1-abc"
Vary: Accept-Encoding

读法:Age: 421 说明这份副本已在共享缓存中存在约 421 秒,未超过 s-maxage=600,本次由缓存给出;到期后客户端可用 ETag 换 304。Vary: Accept-Encoding 意味着压缩与未压缩版本分开存,属正常维度。

这套判断在什么情况下会失效#

  • 各厂商用于标记命中状态的响应头名称与取值不同,不能跨 CDN 套用同一套对照表,需查文档。
  • 清除缓存的生效时间、预热是否真的提前拉取,属厂商实现细节,待核实。
  • 命中率是统计量,必须连同统计口径、时间窗与比较基期一起看;没有这些信息时,它不能证明加速有效。
  • 高命中率也不必然等于体验变好:小对象命中率再高,也掩盖不了回源链路上的慢请求。

结论可以收缩成一句:先确认响应由谁给出,再谈 TTL 与缓存键。头读不对,后面所有调参都缺少依据。

作者:沐小悠

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

更多文章 GET 示例接口

「」标签下的其他文章