cf-cache-status 实测:27 个首页里 13 个不发 age,你看不出这份拷贝有多旧

cf-cache-status 在 27 个首页里只有 8 个站会发,4 个 HIT 对 4 个 DYNAMIC。更值得看的是另一个数:13 个站连 age 都不发,你手里这份 HTML 在缓存里躺了多久,从响应上看不出来。2026-09-01 各请求一次的第一方数据。

改写与发布6 分钟读完2585 次阅读
cf-cache-status 实测:27 个首页里 13 个不发 age,你看不出这份拷贝有多旧

实测 · 2026-09-01 · 27 个首页 · 各请求一次 · 缓存状态响应头

样本 / 口径:30 个站在 2026-09-01 各发一次 GET,桌面 Chrome UA,跟随跳转,不执行 JavaScript,最终响应里的缓存相关头全部落盘。三个站掉出去了 —— stackoverflow.com 与 medium.com 返回 403,reddit.com 只回了 8,393 字节的空壳。剩 27 个。

27 个首页里 13 个不发 age。也就是说,你刚拿到的这份 HTML 在某个缓存里躺了多久,从响应上根本看不出来。另外 14 个发了,最大的一个是 70,780 秒。至于「这次是哪一层回答的」,有 20 个站会说,其中 8 个用的是 cf-cache-status,值是 4 个 HIT 对 4 个 DYNAMIC。

怎么测的

每个首页一次 GET,桌面 Chrome UA,跟随跳转,全程不执行 JavaScript。最终响应里出现下面五个头名之一,就算这个站报了缓存状态:cf-cache-statusx-vercel-cachex-cachex-cache-statusx-nextjs-cache。每个响应的 ageserver 也一并记下。

出口节点在日本大阪。这一条属于口径,不属于脚注:缓存状态说的是某一个边缘节点在某一个瞬间的情况,同一个地址从法兰克福发出去会落到另一个节点,那个节点手里握着哪一份拷贝,这次没测。全部数据都是每站一次请求、桌面浏览器 UA,不是 Googlebot。

13 个站不发 age,拷贝有多旧看不出来

27 个首页里 14 个发了 age,13 个没发。没发的那 13 个,响应本身回答不了一个很朴素的问题:这份东西在缓存里放了多久才到我手上。

首页age(秒)
webflow.com70780
www.wikipedia.org38955
react.dev18841
www.netlify.com15668
railway.com9245
supabase.com6980
developer.mozilla.org897
www.theverge.com555
www.nytimes.com289
vercel.com207
www.wired.com51
nextjs.org44
www.cloudflare.com1
www.notion.com0

最大的一个是 webflow.com 的 70,780 秒,约 19.7 小时;其次是 www.wikipedia.org 的 38,955 秒,约 10.8 小时。这两个数字只说明一件事:这一份拷贝在缓存里待了这么久才送到大阪。它不是这个站的更新频率,也不代表这段时间里内容变过或者没变过。另一头 www.notion.com 是 0、www.cloudflare.com 是 1,信息量同样有限。

更麻烦的是没有 age 的那 13 个。在它们身上,一个 HIT 只告诉你「有缓存回答了你」,然后就没有下文 —— 缓存里那份东西是一秒钟前生成的还是上周生成的,这个头长得一模一样。

cf-cache-status 的 8 个站:4 个 HIT,4 个 DYNAMIC

27 个站里有 8 个在这次请求里发了 cf-cache-status,正好对半分。

站数首页
HIT4about.gitlab.com · astro.build · webflow.com · www.cloudflare.com
DYNAMIC4linear.app · substack.com · www.notion.com · www.wired.com

对半分这件事本身值得说,因为这两个值不是一张成绩单。DYNAMIC 常被读成「没缓存住」,这是它最容易招来的误解。它的意思是这条响应按现行规则本来就不进缓存,所以直接回源了。一个首页只要是个性化的,或者 HTML 重新生成本来就便宜,它就会一直报这个值,而这没有任何问题。

缓存状态头告诉你的是这次请求由哪一层回答,它既不说明页面快,也不说明页面旧。

x-cache 九个站,九家写法对不上

另外四个头名表达的是同一件事,但没有共用一套词汇。x-cache 覆盖面最广,也最没有统一格式 —— 九个站写出了六种形态。

响应头站数取到的值
x-cache9HIT · HIT, HIT · MISS, HIT, HIT · Miss from cloudfront · Hit from cloudfront · cp5017 hit, cp5017 hit/794515
cf-cache-status8HIT ×4 · DYNAMIC ×4
x-vercel-cache5HIT ×4 · MISS ×1
x-nextjs-cache1HIT,在 linear.app
五个头都不发6arstechnica.com · github.com · news.ycombinator.com · slack.com · stripe.com · www.framer.com

四行加起来 23 个头,落在 20 个站上。差出来的 3 个正是同时暴露两层的三个站:www.notion.com 是 cf-cache-status: DYNAMICx-vercel-cache: MISSage: 0;www.wired.com 是同一个 DYNAMIC 配 x-cache: Hit from cloudfront;linear.app 是同一个 DYNAMIC 配 x-nextjs-cache: HIT。后两个站前后两层的说法是反的 —— 前面那层说没缓存,后面那层说命中了,而两句话对各自那一层都成立。

www.figma.com 是从另一侧看到的同一种叠层:x-cache: Miss from cloudfrontx-nf-request-id 一起到达,也就是 CloudFront 前置了 Netlify。还有一个站两边都不算 —— www.netlify.com 发 age: 15668,状态头一个都不发,你能看到这份拷贝已经放了几个小时,却不知道它放在哪一层。

server 头是同一个问题的弱化版:27 个里 cloudflare 7 个、Vercel 4 个、nginx 3 个、干脆不发 4 个,剩下九个各报各的(Google Frontend / github.com / railway-hikari / Apache / BBC-GTM / Framer / Netlify / envoy / ATS)。知道谁站在前面,不等于知道前面那位对你这次请求做了什么。

Googlebot 自己也在缓存

Google 那份 JavaScript SEO 基础文档(2026-09-01 访问)写得很直白:「Googlebot caches aggressively in order to reduce network requests and resource usage. WRS may ignore caching headers. This may lead WRS to use outdated JavaScript or CSS resources.」

把这句话和上面那 20 个站放在一起看。你在响应头上读到的状态,描述的是某个边缘节点对某一次浏览器请求做了什么;渲染器实际用了哪一份 JS 和 CSS,是 Google 内部另做的决定,发生在另一个时刻 —— 同一页还写着 headless Chromium 要等「once Google's resources allow」才渲染。你看到的命中状态,和渲染时真正用上的那份拷贝,是两件事,而你只看得见其中一件。

独立站要做的三件事

三步,第一步只要一次请求。

  1. 先读自己的头:curl -sI https://你的域名/ | grep -iE 'cf-cache-status|x-cache|x-vercel-cache|^age:'。什么都不回,说明你在那 6 个站的组里,关于缓存的所有问题都得去响应之外找答案。
  2. 三十秒后把同一条命令再跑一次。先 MISS 后 HIT,说明规则是生效的,第一次只是碰上了冷节点;两次都 MISS,说明规则根本没匹配上。单独一次读数价值很低,这也是本文这 27 个站只算一张快照、不算排名的原因。
  3. 想清楚你的 HTML 到底该不该被缓存。本来就不该,DYNAMIC 就是正确答案,力气要花在别处 —— 花在回源本身的耗时上,那是 30 个站的首字节耗时实测;以及花在让爬虫少下载一次的校验器上,那是 27 个首页的 http 缓存头实测

还有一层关系值得说。给你发 HTML 的那个边缘节点,通常也是决定 AI 爬虫能不能拿到响应的那个节点,两套规则在同一个后台里 —— 这正是 CDN 在挡 AI 爬虫 讲的那件事。这两样改了哪一样,页面都得被重新抓一次改动才算数,这一步归 推送收录

这次没测出来的几件事

这 27 个站对 Googlebot 会不会报同一个状态,不知道。我们用的是桌面 Chrome UA,没有用爬虫 UA 请求过,也没有对同一个页面做冷节点与热节点的两次对比,所以这些缓存规则对自动化流量是不是同一套,这次没测出来。一次请求、一个大阪出口、一个上午 —— 上面每一个数字都只站在这个基础上,这也是本篇最大的局限。这里的一个 HIT,一分钟后落到一个刚被清过的节点上就可能变成 MISS,反过来同样成立。

常见问题

你们是怎么测的?

2026-09-01 从日本大阪的出口节点对每个首页发一次 GET,桌面 Chrome UA,跟随跳转,不执行 JavaScript,从最终响应里读 cf-cache-statusx-vercel-cachex-cachex-cache-statusx-nextjs-cacheageserver。请求 30 个站,纳入 27 个。

cf-cache-status DYNAMIC 是什么意思?

这条响应按现行规则不进缓存,请求被直接送到了源站。2026-09-01 这次,8 个带这个头的站里有 4 个是这个值,linear.app 和 www.notion.com 都在其中。个性化的首页报这个值是预期结果,不是故障。

age 头是什么意思?

你收到的这份拷贝在缓存里待了多少秒。27 个首页里 14 个发了,最大的是 webflow.com 的 70,780 秒。它说的是这一份拷贝,不是这个站的更新频率。

缓存命中会影响排名吗?

一个 HIT 只说明这次是边缘节点回答的,不是源站。它是关于一次请求的事实,不是页面的属性。本次没有测任何与排名有关的东西,也不打算把排名结论读进这个头里。

Googlebot 看到的缓存状态和我看到的一样吗?

这次测不出来,因为我们没有用爬虫 UA 发过请求。Google 那份 JavaScript SEO 文档(2026-09-01 访问)明写「WRS may ignore caching headers」,所以渲染器眼里的新鲜度,和你响应头上的那个值,是两回事。

cf-cache-status 实测:27 个首页里 13 个不发 age,你看不出这份拷贝有多旧