CDN缓存命中怎么看?HIT、MISS和Age怎么理解
CDN已经接入,静态文件也能正常访问,但打开响应头一看:
CF-Cache-Status: MISS
Age: 0刷新一次,又变成:
CF-Cache-Status: HIT
Age: 18很多人看到这里会开始犯嘀咕:第一次 MISS 是不是说明CDN没有生效?Age: 18 是缓存还剩18秒,还是这个文件已经存在18秒?如果一直没有 Age,是不是所有请求都在回源?
其实,判断CDN缓存不能只截取一个字段,也不能只请求一次。你需要把缓存状态、Age、缓存控制头、请求URL和检测节点放在一起看。
先给出最短的答案:
字段或状态 | 通常表示什么 | 不能直接得出什么结论 |
|---|---|---|
| 当前缓存层找到了可复用的响应,并直接提供给本次请求 | 不代表所有地区、所有URL都命中 |
| 当前缓存层没有找到可直接使用的对象,需要向上游取内容 | 不一定表示每一层都没有缓存,也不等于CDN没生效 |
| 响应自源站生成或最近一次成功验证后,估算已经过去18秒 | 不是响应耗时,也不一定是剩余TTL |
下面把这三个概念拆开讲清楚。
先确认:你看到的是哪家CDN的缓存头
HIT 和 MISS 是常见叫法,但CDN缓存状态并没有一个所有厂商完全一致的响应头名称。
你可能看到:
CF-Cache-Status: HIT也可能看到:
X-Cache: Hit from cloudfront还可能是某家厂商自己的 X-Cache-Status、X-CDN-Cache,或者只在控制台和访问日志里提供结果。相同单词在不同厂商、多层缓存和反向代理中的具体含义,也可能略有差异。
所以第一步不是死记字段,而是先确定:
当前域名使用了哪家CDN;
哪个响应头是这家CDN提供的;
网站前面是否还有另一层CDN、负载均衡或反向代理。
如果厂商不确定,可以先用 CdnChart CDN检测 查看CNAME、响应IP、ASN和HTTP响应头等线索,再对照厂商官方文档解释缓存状态。关于识别逻辑,也可以阅读如何判断网站使用了哪家CDN。
HIT是什么意思?
HIT 的核心含义是:当前负责响应的缓存层里,已经有一个满足本次请求条件、仍然可以使用的缓存对象。
请求过程大致是:
用户请求 → CDN节点查找缓存 → 找到可用对象 → 直接返回与回源获取完整文件相比,缓存命中通常可以减少源站请求和跨区域传输。
不过,看到一次 HIT,只能证明这一次请求、这个URL、这个节点的缓存命中了。
它不能证明:
其他城市或运营商的节点也已经缓存;
首页引用的所有图片、脚本和接口都命中;
不同查询参数、Cookie或请求头使用同一份缓存;
整个网站的缓存命中率很高;
当前配置一定安全、合理。
例如下面两个URL,在很多配置中属于两个不同的缓存键:
https://example.com/app.js?v=100
https://example.com/app.js?v=101即使第一个URL已经 HIT,第二个URL第一次访问仍可能 MISS。如果系统给每次请求都追加随机参数,那么缓存就很难被复用。
MISS是什么意思?是不是一定回源了?
MISS 通常表示:当前缓存层没有找到可以直接用于本次请求的对象。
最常见的过程是:
用户请求 → 边缘节点未命中 → 从源站获取 → 返回并按规则缓存所以,新文件第一次被某个节点访问时出现 MISS 很正常。只要响应允许缓存,第二次请求同一个URL,就可能变成 HIT。
但在现代CDN架构里,不能把所有 MISS 都简单翻译成“这次请求一定直接打到源站”。
原因是CDN可能存在两级甚至多级缓存:
用户 → 边缘节点 → 上层缓存 / Origin Shield → 源站边缘节点本地没有对象,可以记一次本地 MISS;但上层缓存可能已经有内容,于是请求由上层缓存满足,源站并没有再次传输完整文件。
不同厂商暴露的是本地层、最终层还是汇总状态,要以其文档和日志为准。
此外,当多个用户几乎同时请求一个尚未缓存的大文件时,一些CDN会合并这些回源请求:第一个请求负责填充缓存,其余请求等待并复用结果。AWS在CloudFront自定义源站请求行为中将这种机制称为request collapsing,可以避免每个并发请求都单独访问源站。
因此,判断请求是否真正到达源站,最可靠的证据通常来自:
CDN控制台的回源请求数和回源流量;
CDN访问日志中的详细缓存状态;
源站访问日志;
Origin Shield或上层缓存指标。
单个客户端看到的一个 MISS,只是线索,不是整个缓存链路的完整账单。
Age是什么意思?
Age 是标准HTTP响应头,单位是秒。
根据 RFC 9111 HTTP Caching,它表示缓存对“自响应由源站生成或最近一次成功验证以来已经过去多少秒”的估算。这个数值还会计入响应在缓存链路中的停留时间和传输时间。
例如:
Cache-Control: public, max-age=3600
Age: 600可以粗略理解为:这份响应自生成或验证后已经过去约600秒。
如果没有其他缓存策略覆盖,并且 max-age=3600 确实是共享缓存采用的TTL,那么理论上还剩约3000秒的新鲜时间:
3600 - 600 = 3000秒但这只能作为近似判断。
CDN可能配置了独立的边缘TTL,可能优先读取 s-maxage 或 CDN-Cache-Control,也可能存在分层缓存、重新验证和厂商自定义规则。所以,不能只凭 Age 反推最终过期时间。
Age不是什么
Age 很容易被误读。它不是:
本次请求花费的时间;
文件从创建至今的年龄;
DNS缓存的TTL;
缓存还剩多少秒;
CDN节点运行了多久;
静态资源的版本号。
Age: 120 不代表页面加载用了120秒,也不代表缓存只剩120秒。
Age为什么会越来越大?
在同一个缓存节点连续访问同一个URL时,如果每次都复用同一个缓存对象,Age 往往会随时间增大:
# 第一次
CF-Cache-Status: HIT
Age: 21
# 几秒后
CF-Cache-Status: HIT
Age: 27这是比较典型的正常命中表现。
Age为什么会突然变小或归零?
常见原因有:
请求被调度到另一个边缘节点;
缓存被主动清除;
对象过期后重新从源站获取;
缓存对象被淘汰,再次填充;
CDN向源站重新验证后重置了年龄;
多层缓存返回了不同层的年龄信息。
Cloudflare在缓存响应状态说明中指出,其 Age 会在重新验证、清除或驱逐后重置;使用分层缓存时,还可能继承上层缓存的 Age。
没有Age是不是就没有命中?
不是。
RFC 9111同时提醒:没有 Age,不能据此断定请求一定联系了源站。某些缓存或代理可能不公开该字段,某些响应状态也可能不带它。
反过来,有 Age 也不该脱离其他字段单独判断。有的上游代理或源站会传来自己的 Age,CDN也可能把它继续传递。
最好同时查看缓存状态、Via、厂商特征头和缓存控制策略。
除了HIT和MISS,还会看到哪些状态?
不同厂商的名称并不完全相同。下面是常见语义和典型示例,解释具体网站时,应以对应厂商的官方定义为准。
状态 | 常见含义 | 排查重点 |
|---|---|---|
| 找到可用缓存并返回 | 再看Age是否合理、不同地区是否一致 |
| 当前缓存层没有可直接使用的对象 | 首次访问、缓存键、TTL、是否成功写入缓存 |
| 对象原本可能进入缓存流程,但因响应头或规则绕过缓存 |
|
| 请求在查缓存前就被判定为不适合缓存 | URL规则、文件类型、缓存模式、动态页面 |
| 已有对象过期,需要从上游取得新响应 | TTL是否过短、源站是否正常 |
| 上游确认内容未变化后继续使用缓存 |
|
| 缓存已过期,但在特定条件下仍返回旧副本 | 源站故障、stale策略、一致性要求 |
| 先返回旧缓存,同时在后台更新 | 是否开启后台刷新 |
| 响应在常规缓存流程之前产生,或未得到可识别状态 | WAF、边缘函数、重定向和错误页 |
这里有两个容易混淆的点。
第一,BYPASS 和 DYNAMIC 都可能表现为请求去了上游,但原因不同:前者通常是响应头或规则让对象不被缓存,后者可能在请求阶段就被认定为动态内容。
第二,REVALIDATED 不等于重新下载整个文件。
CDN可以通过 If-None-Match 或 If-Modified-Since 向源站确认内容是否变化。如果源站返回 304 Not Modified,缓存便可以继续使用原对象。
CloudFront的日志中也使用 RefreshHit 表示对象过期后向源站确认,并继续使用缓存对象,具体定义可查阅AWS CloudFront标准日志字段。
怎样实际检查CDN缓存是否命中?
最实用的方法不是在浏览器里反复按刷新,而是固定条件,连续请求同一个公开静态资源。
第一步:选择适合测试的URL
优先选择:
公共CSS或JavaScript文件;
网站Logo、图片或字体;
明确允许CDN缓存的下载文件;
不需要登录、Cookie或授权头的资源。
不要一开始就拿首页、登录页、购物车或API接口测试。它们可能本来就不应该被共享缓存。
为了追求 HIT 而缓存私人页面,反而可能造成用户数据泄露。
第二步:查看完整响应头
把示例URL替换成你的真实静态资源:
curl -sS -D - -o /dev/null https://www.example.com/assets/app.css参数含义:
-D -:把响应头输出到终端;-o /dev/null:不保存响应正文;-sS:减少进度信息,但保留错误提示。
有人习惯使用 curl -I 发送HEAD请求。它适合快速查看响应头,但有些CDN、源站或缓存规则对HEAD和GET的处理不同。
排查真实浏览器访问时,用GET请求并丢弃正文通常更接近实际情况。
重点观察这些字段:
Cache-Control: public, max-age=3600
CDN-Cache-Control: max-age=86400
CF-Cache-Status: HIT
X-Cache: Hit from cloudfront
Age: 245
ETag: "abc123"
Last-Modified: Thu, 10 Sep 2026 08:00:00 GMT
Via: ...第三步:连续请求同一个URL
for i in 1 2 3; do
printf 'Request %s\n' "$i"
curl -sS -D - -o /dev/null https://www.example.com/assets/app.css \
| grep -Ei '^(cache-control|cdn-cache-control|age|via|x-cache|cf-cache-status|etag|last-modified):'
sleep 2
done测试时要保持这些条件一致:
完整URL相同,包括大小写和查询参数;
不要每次附加随机时间戳;
请求方法相同;
不要一会儿带Cookie,一会儿不带;
不要主动发送
Cache-Control: no-cache,除非正在测试重新验证;尽量在短时间内从同一网络连续请求。
Google Cloud CDN的故障排查文档同样建议使用 curl -s -D - -o /dev/null URL 查看响应头,并以 Age 等字段辅助确认缓存响应。
连续测试结果应该怎么判断?
下面几种模式比单次结果更有参考价值。
连续结果 | 常见解释 | 下一步 |
|---|---|---|
第一次 | 节点首次取回后成功缓存 | 再测试其他地区和关键资源 |
连续多次都是 | 对象未写入、缓存键变化、TTL过短或频繁淘汰 | 检查缓存头、规则、参数和日志 |
一直是 | 内容按规则未进入共享缓存 | 确认是业务设计还是配置错误 |
| 可能切换节点、清缓存、重新验证或重新填充 | 同时记录响应IP、节点和时间 |
一个地区 | 不同节点拥有独立缓存 | 各地区连续测试 |
外层显示 | 可能存在多层CDN或残留响应头 | 结合IP、CNAME和日志判断 |
浏览器显示 | 浏览器或中间缓存进行了条件验证 | 不能自动等同于CDN |
最理想的结果一定是“全部HIT”吗?
不是。
公开的版本化静态资源适合长期缓存,高命中通常是好事;但登录接口、个人资料、订单、购物车和实时权限数据,本来就不应该被不同用户共享缓存。
缓存优化的目标不是让所有URL变成 HIT,而是让应该缓存的内容稳定命中,不应该共享的内容始终保持隔离。
为什么CDN一直MISS?
如果同一个静态资源连续测试仍然 MISS,可以按下面顺序排查。
1. 响应本身不允许共享缓存
检查源站和CDN返回的:
Cache-Control: private
Cache-Control: no-store
Cache-Control: no-cache
Cache-Control: max-age=0
Set-Cookie: ...这些字段的影响并不完全相同:
no-store表示不应存储响应;private表示共享缓存不应存储,只可由私有缓存处理;no-cache并非“绝对不能存”,而是复用前需要验证;max-age=0会让响应立即变得不新鲜;Set-Cookie在部分CDN默认策略中会导致绕过缓存。
不要盲目删除这些头。先确认它们是否在保护用户状态和敏感内容。
2. 每次请求使用了不同的缓存键
常见原因包括:
URL查询参数变化;
Host不同;Cookie被纳入缓存键;
Authorization请求被单独处理;Accept-Encoding、语言或设备头参与缓存变化;Vary导致缓存被拆成多个版本。
Google Cloud CDN的缓存工作原理指出,URL、查询参数和被纳入缓存键的请求头都会影响对象能否复用。
一个页面看似请求同一文件,实际缓存键可能一直在变化。
3. 缓存规则没有覆盖这个URL
检查路径、扩展名、响应状态码和请求方法是否符合CDN规则。
常见情况是只缓存 .jpg、.css、.js,而实际文件使用了没有扩展名的动态路径;或者规则优先级被另一条“绕过缓存”配置覆盖。
4. TTL过短或对象被频繁淘汰
如果TTL只有几秒,下一次请求到达时对象可能已经过期。
冷门对象也可能因为节点容量策略被提前淘汰,因此缓存时间上限不等于保证驻留时间。
5. 每次访问的不是同一个节点
Anycast、DNS调度、多CDN和IPv4/IPv6差异,都可能让连续请求进入不同节点。
测试时可以同时记录远端IP:
curl -sS -D - -o /dev/null \
-w 'remote_ip=%{remote_ip} total=%{time_total}\n' \
https://www.example.com/assets/app.css如果响应IP不断变化,Age和缓存状态重置就更容易解释。
6. 测试的是HTML、接口或带身份状态的请求
许多CDN默认缓存静态文件,却不默认缓存HTML和动态接口。此时持续 DYNAMIC 或 BYPASS 可能正是预期结果。
先拿已知可缓存的公共静态资源建立基准,再排查动态内容。
为什么不同地区看到的HIT、MISS和Age不一样?
CDN的缓存不是全球只有一份。
北京、新加坡、法兰克福和洛杉矶的用户可能进入不同的边缘节点,每个节点的访问热度、填充时间和淘汰状态都不同。
因此,同一个URL可能同时出现:
地区 | 缓存状态 | Age | 可能情况 |
|---|---|---|---|
北京 |
| 850 | 当地访问频繁,缓存较热 |
新加坡 |
| 42 | 最近刚填充或重新验证 |
法兰克福 |
| 无 | 该节点首次访问或对象已被淘汰 |
这并不矛盾,也不代表某个检测点出错。
可以先用 CdnChart网站测速 对同一URL做多地区测试,查看各地区的响应IP、耗时和访问差异,再结合自己用 curl、浏览器开发者工具或CDN日志取得的缓存响应头判断。
CdnChart的探测口径可以在测评方法说明中查看。
需要注意:一次跨地区测试仍然只是各节点当时的快照。要判断缓存是否稳定,最好固定URL,在相同地区连续测试,并记录时间、IP和缓存状态。
一次HIT不等于缓存命中率高
单次响应只能回答“这一次是否命中”,不能回答“网站整体缓存效果如何”。
CDN控制台里常见的命中率还可能分为:
请求命中率:被缓存满足的请求数,占符合统计口径请求数的比例;
字节命中率:由缓存提供的流量,占总传输字节数的比例。
例如,大量小图标命中,但几个大文件频繁回源,请求命中率可能很好看,字节命中率却不高。
反过来,一个大视频命中也可能显著抬高字节命中率。
此外,不同厂商对动态请求、错误响应、不可缓存请求和上层缓存命中的统计口径可能不同。跨厂商比较前,应先核对指标定义,不要只比较一个百分比。
真正值得长期观察的是:
关键静态资源的请求命中率和字节命中率;
回源请求数、回源流量与回源错误率;
不同地区、路径和文件类型的命中差异;
缓存清除、发布和版本更新后的变化;
源站负载是否随命中提升而合理下降。
常见问题
第一次MISS、第二次HIT,说明CDN正常吗?
通常说明当前节点完成了缓存填充,是正常的冷缓存到热缓存过程。但仍需检查对象TTL、其他地区节点和长期命中率。
MISS是不是说明CDN加速没有生效?
不是。请求已经到达CDN,只是当前缓存层没有可复用对象。
CDN仍可能提供TLS终止、连接优化、安全防护或上层缓存等能力。
Age为0是HIT还是MISS?
只看 Age: 0 无法判断。它可能是一份刚写入或刚完成重新验证的缓存,也可能来自其他代理。
应同时查看厂商缓存状态头和日志。
Age越大是不是访问越慢?
不是。Age表示响应的缓存年龄,不是请求耗时。
性能要看DNS、连接、TLS、TTFB和总下载时间等指标。
Age超过max-age为什么还能收到内容?
可能发生了重新验证、允许返回stale内容、存在上层缓存策略,或者看到的 max-age 并非CDN最终采用的边缘TTL。
需要结合 s-maxage、CDN-Cache-Control、厂商配置和缓存状态分析。
浏览器强制刷新后变成MISS,配置坏了吗?
不一定。
强制刷新可能携带要求重新验证或绕过本地缓存的请求头,也可能触发不同的CDN处理。排查时应使用固定的普通GET请求,避免把浏览器缓存和CDN缓存混为一谈。
如何确认请求真的访问了源站?
查看源站访问日志、CDN回源日志和回源指标最可靠。
客户端的 MISS 可以提示你继续调查,但无法完整描述多层缓存内部发生了什么。
总结:缓存命中要看一组证据,不是一个单词
记住三个核心结论:
HIT表示当前缓存层找到了可复用对象,但只代表本次请求和当前节点;MISS表示当前缓存层未命中,不等于CDN没生效,也不一定能证明每个请求都直达源站;Age表示响应自生成或最近一次验证后经过的估算秒数,不是响应时间,也不是天然的剩余TTL。
实际排查时,选择一个公开静态资源,保持URL和请求条件不变,连续请求三次;同时记录缓存状态、Age、Cache-Control、响应IP和检测时间。
然后再换地区验证,并用CDN控制台或源站日志确认是否真正回源。
如果还不确定域名接入了哪家CDN,可以先使用 CdnChart CDN检测 查找厂商线索;如果想比较不同地区的访问节点和速度,可以使用 CdnChart网站测速。
把缓存响应头与多地区测速结果放在一起,远比看到一次 MISS 就下结论更可靠。
- CDN怎么看是否命中缓存
- CF-Cache-Status HIT什么意思
- CDN一直MISS怎么办
- Age响应头是什么意思