跳到正文
AtomStorm
研究笔记v1.0发布于 2026-09-09核验于 2026-09-09方法 1.0

Cloudflare Pages 里哪些重定向规则会静默失效

我们在本地 Pages 模拟器上测了 48 种 _redirects 规则写法,每条发三次请求,另设四组对照。26 种从未生效——但其中只有 11 种在每一层都是静默的。这 11 种共用一个形态,而那并不是文档警告你的那个形态。

本页如何生产

由 AI agent 起草。 由与生产方不同模型族的模型逐条对照来源与原始数据做了对抗式审查,无未决 P0。尚未经人工通读。 证据最近核验于 2026-09-09。

吵闹着失败的重定向规则,你一分钟就修好了。被接受、被算作有效、然后一次都匹配不上的 重定向规则,你要花一个季度才发现——还是从流量图上发现的。

这页报告的是一个矩阵的一次实测。范围局限放在下面的框里,不塞进脚注——它们决定这个 结果能担多重的分量。

范围。 下面 144 次请求全部打向本地 Pages 模拟器wrangler 4.65.0),不是 Cloudflare 的生产边缘节点。这里没有任何一条是在论断 Cloudflare 在生产环境里会 怎么做。它:一条证据——某种规则写法可以通过你能想到的每一道检查,然后什么也不 做。这就是不该把关键路径押在未成文行为上的理由,跟你测的是哪一层无关。

我们做了什么

我们在跑任何东西之前,先把方法写下来并冻结。冻结的那份文件随数据一起发布;它的 前十个章节哈希为 edc553bc3dca31a760c2c109dea9a9c5,跑之前和跑之后都是这个值。发布的 那份多了一段原始文件没有的溯源头,所以它会印出复现这个哈希的精确 offset 命令—— 自己去核,别听我们怎么说。

矩阵是源写法(4)× 目标写法(3)× 状态(4)= 48 条规则,每条请求三次:

维度取值
/rNN/ · /rNN/* · https://atomstorm.ai/rNN/ · //atomstorm.ai/rNN/
目标/en/ · https://example.com/ · //example.com/
状态200 · 301 · 302 · 省略

每条规则有自己的源前缀,彼此不会互相遮蔽。

发不发,由对照组说了算

四组对照在同一个环境里跑,预注册里写明:任何一组不过,整轮作废:

对照预期实测
C1 —— 一个正常页面,不挂规则200200,88,947 B
C2 —— 本站现有的一条 301301,指向正确目标301/en/journal/
C3 —— 一条不存在的路由404404,8,494 B
C4 —— 撤掉 48 条测试规则,重跑 C1–C3不变不变

四组全过。真正要紧的是 C4:它说明那 48 条测试规则本身没有动过基线,而这是另外 144 次测量还有意义的唯一理由。

我们发现了什么

48 种写法里,22 种有效,26 种无效——下面那张表就是这个拆分,数目对得上: 48 = 22 + 15 + 11。要紧的是,「无效」其实是两种截然不同的东西:

结果条数你会看到什么
有效22——(其中两条返回 200,但内容字节是错的——见下文)
解析阶段就被拒15启动时 wrangler 点出文件名、行号和原因
每一层都静默11什么都没有。哪儿都没有。

那 15 条吵闹的失败没有问题

15 条全部落在两种形态里。 两种都会在启动时报出名字,任何一份部署日志里都看得见:

  • 跨域目标配 200 ——Proxy (200) redirects can only point to relative paths
  • 绝对 URL 作源 ——Only relative URLs are allowed. Skipping absolute URL …

这些都是按设计工作的。你写了不支持的东西,工具告诉了你,还带了行号。

那 11 条静默的共用一个形态

每一条静默写法都用的是协议相对源——//host/path,而不是 /path

//atomstorm.ai/r37/  /en/  200

这条规则被算进有效规则Parsed 38 valid redirect rules),不产生任何警告一次请求也匹配不上。绝对 URL 过不了「以 / 开头」那道检查,它却过得去,于是从 抓住它那个吵闹同类的检查底下溜走了——然后路由器永远匹配不到它。我们的理解是, //host/path 被当成一条字面路径,而你站上并不存在那条路径;我们测到的是静默本身, 不是 wrangler 的匹配逻辑。

写下了,收下了,静默,死了。

为什么这种比吵闹的失败更糟。 一条规则被拒,代价只是一行部署日志。一条收下了 却不动的规则,代价是原本会到老 URL 的那些流量——一直付到有人察觉为止。没有错误 可以 grep,规则计数还涨了,所以「我的重定向加载了吗」这种体检会告诉你:加载了。

两种写法返回 200,但内容是错的

//example.com/ 配状态 200,三次请求三次都返回 200——但正文是 5,321 字节, 与我们自己的 index.html 逐字节相同。不是代理。不是错误。同一个 //example.com/ 写成 301302,产生的是一次真正的跨域重定向;也就是说,同一个目标字符串, 会随状态码不同被解读成两种东西

我们把这两条记成 effective,因为跑测前定好的评分表就是这么规定的,而且看到正文 之后我们没有回头改分。评分表把「任何带非空正文的 200」当作成功,这是它错了;这个 缺陷记在方法的偏差日志里,而不是从表里抹掉。

我们没发现什么

预注册列了三个假设。两个得到证实,还有一个也得到证实,但附带的说明让既有文档变得 更不准确,而不是更准确:

  • 跨域 200 不走代理——已证实,并且在更大的样本上复现了此前的一次单独观察。
  • 跨域 301/302 确实有效——已证实
  • 绝对 URL 作源无效——已证实,而且解析阶段的日志解掉了我们事先标出的一个歧义 (模拟器的 Host 不是我们的域名,所以单看请求层的 404,分不清「解析时就被忽略」和 「匹配上了但主机不对」)。

协议相对这条发现不在预料之内。 它是填矩阵时掉出来的。我们把它作为探索性观察 报告,不作为已证实的假设——因为它本来就不是。

怎么用

去查你自己的 _redirects 里有没有协议相对源——开头写成 // 的那种。我们写的每一条 在模拟器里都是死的,而没有任何一层说过话。我们没有测生产环境——这是论据本身,不是 它的缺口:一种能死得这么安静的写法,不该有活路径押在它上面。

我们把这条发现做成了本站的构建门,而不是一条习惯:seo-verify 现在会拒掉任何不是 站内相对的 _redirects 源,以及任何跨域 200。留在报告里的发现会被忘掉;接进门里的 发现,每次构建都会被强制。

复现

需要的东西全都发布了:48 条规则、全部 144 行实测记录(每行带 run id、脚本 commit 和 精确命令),以及冻结的方法。这一轮的第一遍尝试作废了,因为一个 shell read 循环 丢掉了最后一行,第 48 条规则一次都没被请求——这件事在看到任何结果之前就被抓到了, 作废的原始数据和原因都留在记录里。

来源