小流量灰度之所以能暴露全量发布的例外,是因为它把“首选域名生效”从配置层面的判断,变成了对真实请求路径的抽样验证。你手里已有的材料通常是一份跳转规则、一组灰度名单,以及一个尚未全量放开的页面。问题往往不在主规则本身,而在灰度命中的那部分请求走了另一条链路:CDN 边缘、反向代理、应用层中间件或旧域名解析,其中任何一处没有继承首选域名的判断,全量时就会以更高比例放大成例外。
常规做法是检查源站配置里是否写了 301 到首选域名,但灰度环境经常在源站之前就分流了。你需要拿到灰度名单对应的实际入口,而不是配置页上写的入口。具体动作是:从灰度名单中挑一个可复现的 URL,用命令行请求它,记录状态码、Location 响应头和最终落地的域名。
如果状态码是 200 且落地域名不是首选域名,说明这条请求根本没有进入跳转规则。此时下一步不是去改跳转规则,而是先确认灰度流量在 CDN 或负载均衡层被路由到了哪个后端。反过来,如果状态码是 301 且 Location 指向首选域名,但页面内容仍来自旧域名,那问题在跳转之后,属于应用层生成绝对链接或资源地址时没有跟随首选域名。
这两类例外在全量发布时的表现完全不同,处理顺序也不同。
把这两类混在一起排查,会出现“跳转明明对了,为什么全量后还是出问题”的困惑。先分类,再决定是修边缘缓存还是修模板输出。
面向已有经验的读者,真正容易漏的不是主域名规则,而是灰度与全量之间的差异条件。可以按下面顺序核对,每项都要求给出可观察结果,而不是“已配置”这种结论。
其中第三项最容易被忽略。假设灰度后端绑定的是旧域名,而边缘层把首选域名的 Host 传了过去,应用生成绝对链接时就可能回退到绑定域名。这个假设可以用一个短例子说明:请求首选域名,页面内链却指向旧域名,抓取工具顺着内链走到旧域名,旧域名又返回 200,于是例外被固化下来。验证方法是抓取渲染后 HTML,检索内链与 canonical 的域名,而不是只看首屏跳转。
核对完成后,你得到的是三类结论,每类对应不同动作。
注意,灰度期间请求量小,某些例外可能只是采样偏差,不能仅凭一次请求就断定全量必然出问题。反过来,灰度没有复现也不能证明全量安全,因为灰度名单可能恰好避开了某条路由。更稳妥的做法是把灰度比例分档提升,每档都重复上面的请求与抓取检查,直到覆盖到与全量相同的入口组合。
如果时间紧,优先修跳转类例外,因为它的影响面直接、可快速验证。自引用类例外可以稍后处理,但必须在全量前完成,否则抓取工具会沿着旧域名内链持续发现非首选域名页面。一个务实的判断依据是:只要渲染后的 HTML 中仍存在指向非首选域名的绝对地址,就不具备全量条件。
最后要区分“抓取限制”与“索引移除”。即便你在 robots.txt 中限制了旧域名,也不等于旧域名页面会从索引中消失,站点地图也不保证收录。首选域名设置的目标是让规范地址稳定可预期,而不是靠屏蔽旧地址来掩盖例外。把灰度验证的重点放在请求路径与自引用地址上,比事后补救更省力。