cloudflare vary 支持上线了:Cache Rules 里那三个动作该怎么选

cloudflare vary 支持在 2026-09-22 上线,全档位可用,它把一个难题拆成两个好做的决定:源站照旧在 Vary 里点名字段,Cache Rule 决定 Cloudflare 是归一化、原样透传、还是让这份响应不进缓存。默认是归一化。我们 2026-09-26 查了 30 个首页和自己跑的 6 个站。

改写与发布5 分钟读完1930 次阅读
cloudflare vary 支持上线了:Cache Rules 里那三个动作该怎么选

规则变动 · 2026-09-22 · Cloudflare · Vary 现在是一项 Cache Rules 设置

样本与口径:30 个首页 + 我们自己跑的 6 个站,2026-09-26 各一次 GET,桌面 Chrome UA、跟随跳转、不执行 JavaScript;只读响应头。30 个首页里 28 个返回 200。

cloudflare vary 这件事以前没有好答案:Vary 是响应头,它告诉共享缓存「哪些请求字段参与决定了这一份响应」——正文被压缩时通常是 Accept-Encoding,被翻译时通常是 Accept-Language。想要它的 Cloudflare 用户,过去要么绕开缓存,要么自己拼一个 cache key,要么写一个 Worker。2026-09-22 起,Cache Rules 里多了一项设置:源站照旧在 Vary 里点名字段,由规则决定 Cloudflare 怎么处理这个字段的值——归一化、原样透传、还是干脆不进缓存。默认是归一化。

cloudflare vary 支持到底加了什么

它把一个难题拆成了两个好做的决定。源站继续负责在 Vary 里点名可能影响响应的请求头;Cache Rule 负责决定 Cloudflare 怎么看待每一个被点到的字段。Cloudflare 那篇公告把这个头称作「the ugliest part of HTTP that we haven't yet improved」,这句话来自 Mark Nottingham 对 1.2 亿多条响应的分析——说明这个功能不是随手发的。

三个动作的差别,官方文档写得很具体。

动作它做什么什么时候用
normalize匹配前先重写已知的协商类请求头,让等价的请求共用一份缓存。对 Accept、Accept-Language、Accept-Encoding 走各自的专门规则;其余头只去掉多余空白、按原顺序合并重复行。协商类头,很多个请求值其实只对应少数几份响应
passthrough匹配缓存时用请求头的原始字节,大小写、空格、顺序、重复值都各算各的。取值集合可控、且具体值真的会改变响应的头
bypass源站在 Vary 里点到该头时,这一份响应就不进缓存。已经存下的旧条目不会自动删。带个人属性或取值无界的头,例如 Cookie、User-Agent

有两条规则横穿这张表。Vary: * 永远绕开缓存,因为它的意思是「请求的任何部分都可能有关」,连 HTTP 报文之外的东西(比如客户端 IP)都算。另外,改配置不会自动清掉已经存下的东西:请求会按新键重新填,旧条目得过期或被 purge 才会走。

我们在 30 个首页上看到什么

我们想知道这事到底多常见,就在 2026-09-26 抓了 30 个首页各一次,记录它们发回来的响应头。28 个返回 200 的站里,10 个经过 Cloudflare 边缘;这 10 个里有 9 个发 Vary,其中 8 个只发小写的 accept-encoding。

站点Vary 值缓存状态
cloudflare.comaccept-encodingHIT
webflow.comaccept-encodingHIT
discord.comaccept-encodingHIT
wired.comaccept-encodingDYNAMIC
shopify.comaccept-encodingDYNAMIC
notion.comaccept-encodingDYNAMIC
linear.app11 个字段,含 Accept-EncodingDYNAMIC
ycombinator.comX-Inertia,Accept-EncodingDYNAMIC
substack.comAccept-EncodingDYNAMIC
astro.build没有HIT

这个功能想解决的缺口,藏在最后一行和我们自己的站里。我们跑的 6 个站发的是同一条五字段值——rsc、next-router-state-tree、next-router-prefetch、next-router-segment-prefetch 和 Accept-Encoding;它们都不在 Cloudflare 后面,所以今天对我们没有任何变化。但如果这些站挂在 Cloudflare 上,五个字段里有四个是搜索爬虫永远不会发的框架路由字段。把它们写进 Vary,等于为一个可能不需要这种区分的缓存层加宽了缓存键;在这次发布之前,想修就得手工复刻源站的协商逻辑。

有一个数字比看起来小。9 / 10 说的是我们恰好挑中的这一批首页,不是 Cloudflare 全站的比率。我们挑的是开发者味很重的一组站,它代表不了大量把 Cloudflare 用在别处的人。

三个动作到底怎么选

从默认值出发,只有找到理由才离开它。下面这个顺序就是文档暗示的顺序。

  1. 协商类请求头留在 normalize。源站点到了 Accept-Encoding 或 Accept-Language,等价的请求就应该共用一份响应;正是归一化让 en-US, fr;q=0.8 和 fr;q=0.8, en-GB 收拢成同一个变体。
  2. 带个人属性或取值无界的头改到 bypass。Cookie 与 User-Agent 是文档给的例子。一个头可能为每个访客取几千个值,那把它挡在缓存外比给它各存一份便宜。
  3. 只有具体值真的会改变正文时才用 passthrough。它连大小写和空格都分开算,所以拿它去处理一个源站本就视为等价的头,是选错了工具。
  4. 用同一个客户端测,盯 CF-Cache-Status。发几组本应归一化到同一变体的请求,缓存填起来后看是不是 HIT。一直 MISS 或者冒出意外的 BYPASS,就是回头改规则的信号。

不要把同一个头同时放进自定义 cache key 和 Vary,除非你真测过这种重复。文档的规矩是:一个属性如果永远定义了这个资源,就用自定义 cache key;源站在它所有可缓存响应里都会声明同一组请求字段,才用 Vary。

它不做什么

它修不了源站根本没发 Vary 的情况——公告说得很清楚,没有这个头的响应照常缓存。它不会清掉已有内容。而且它不是一个我们能直接观察的东西:我们没有在 Cloudflare 上开这项设置,所以上面所有关于行为的描述都来自 Cloudflare 的文档与公告,而数字来自响应头。我们也没有发不同的请求头去看正文有没有变,所以这一篇量的是站点声明了什么,不是缓存实际存了什么。

最后这个缺口,是这篇诚实的边界。我们数到的声明是真的;对缓存的影响是文档写的,不是我们测的。

常见问题

Vary 这个头到底是干嘛的?

它告诉共享缓存哪些请求字段可能改变响应,免得缓存把一份压缩过的正文发给根本没要压缩的客户端。RFC 9110 的原话是它「expands the cache key required to match a new request to the stored cache entry」。

会不会影响收录?

它不是一个排名输入,也没有任何 Google 文档把它写成排名因素。它影响的是投递:爬虫也是一种请求方,这个头决定了共享缓存把哪一份存好的响应交回去。27 个首页的声明情况数在 Vary header 那篇实测里。

为什么不干脆加一个自定义 cache key?

因为自定义 cache key 会把它的维度加到这条规则覆盖的每一份响应上,不管源站到底用没用。而 Vary 是响应驱动的,只有真的点了这个字段的响应才会被加宽。

你们怎么测的?

2026-09-26 每个首页一次请求,桌面 Chrome UA、跟随跳转、响应头按收到的样子落盘。两个站返回 403 被剔除,纳入 28 个。我们只读声明,没有测任何缓存的实际行为。

这条改动对我们这种技术栈的站最相关:Vary 里那四个路由字段对爬虫是无效的,而在九月之前,在 Cloudflare 上没有一个一行的办法把它说清楚。这些字段协商出来的压缩是哪种,数在 27 个首页的 content-encoding;命中率那一侧在 面板的 CF-Cache-Status;而把这一切变成一次真的发布出去,是 QueryWin 在做的事。

cloudflare vary 支持上线了:Cache Rules 里那三个动作该怎么选