Boloop 阅读示意图(AI 生成):检查第一跳,才能找到验证文件的路由问题。
Google 提供的验证文件已经放进部署包,处理它的 Worker 单测也返回 200,但正式地址仍然不能按预期读取。Boloop 遇到的这次问题,出在请求抵达处理函数之前。
实际观察到的路径是:请求带 .html 后缀的验证文件,先收到 308,跳到去掉扩展名的地址,然后返回 404。文件没有丢失,返回它的代码也没有机会运行。
先看第一跳而不是最终页面
遇到验证失败时,直接在浏览器里打开地址有一个盲点:浏览器通常会跟随跳转。最后显示了一个页面,并不意味着最初那个精确地址直接返回了正确内容。
排查这类端点,我会分别检查 GET 与 HEAD,并保留第一跳的状态码和 Location。GET 用来确认正文,HEAD 用来检查没有正文时的状态与响应头。它们回答的问题不同,不能只凭 HEAD 的 200 就断言文件内容正确。
当时的 308 已经给出了一个很明确的方向:先查平台的路由与静态资源处理,不急着修改 Google 控制台。
Pages 的便利规则与验证地址发生了冲突
Cloudflare Pages 默认会把静态 HTML 地址转到不带扩展名的形式。例如 /contact.html 会转向 /contact。对普通页面来说,这是平台预设的地址形式;对一个必须按指定路径读取的验证端点,就需要单独检查。Cloudflare Serving Pages 文档
Boloop 的构建过程会生成 _routes.json,决定哪些请求进入 Worker、哪些交给静态资源层。验证文件当时被放进排除项,因此请求先进入静态 HTML 处理,触发了去扩展名跳转。
之前的测试直接调用 Worker,绕开了这份分发清单。它证明处理函数能返回文件,却没有证明正式请求一定会到达处理函数。
最小修复是改变这个精确路径的分发
这次没有新增一套通用 HTML 回退,也没有把所有 .html 文件都放行。修改只针对用户提供的那一个验证文件:保留文件原始内容,将它从 Worker 的路由排除项移出,让既有处理函数在平台静态规范化之前直接返回它。
文件只有 53 字节,构建检查同时核对长度和 SHA-256。这里的字节数与哈希是该文件的具体约束,不能复制成其他网站的验证内容;另一个网站应使用自己从 Google 取得的原始文件。
精确例外还有一个好处:它不会顺带改变未知 HTML、后台路由或私有文件的访问方式。一个公开验证端点没有理由扩大整站的静态文件边界。
回归测试必须把路由分发补回来
新的测试读取实际构建产生的 _routes.json,先判断请求是否进入 Worker,再执行对应响应。加入旧的排除项时,测试能重现 308;去掉该精确项后,GET 与 HEAD 应直接返回 200,而且没有 Location。
GET 还要逐字节核对正文,HEAD 则应保持空响应体。测试同时保留普通静态资源仍走静态层、API 仍进入 Worker 等控制样本,避免为了验证文件破坏其他路径。
这一轮有 21 项相关构建与边界测试通过。平台分发在测试里仍属于模拟,部署后的精确地址还要再核验一次。
可复用的排查顺序
先确认文件确实进入最终部署产物,再请求原始地址,查看第一跳。存在跳转时,检查每一跳由哪一层产生;没有跳转但正文不对,再检查路径处理、编码与返回内容。最后才回到验证界面提交结果。
对于 Boloop,这次问题最有价值的线索不是“验证失败”,而是“Worker 单独正常,经过实际分发后不正常”。以后再遇到类似差异,我会先把入口层补进测试,而不是继续增加处理函数里的断言。