小流量灰度能暴露死链接问题的前提是:灰度流量确实经过与全量相同的链接解析、重定向和索引路径,并且你按被替换链接的原始入口分组观察。满足这个前提时,灰度往往能提前暴露一类全量发布才会出现的例外——旧链接在部分路径上被保留、在另一部分路径上被替换,导致同一批死链接的处置结果不一致。若灰度只覆盖新入口、不覆盖旧入口,或只验证页面能否打开而不验证链接去向,这个结论就不成立,灰度反而会给出错误的安全感。
死链接相关的问题通常被笼统归为“404 变多”,但灰度阶段真正有价值的信号是链接去向的变化,而不是状态码本身。同一个旧地址,在全量环境里可能有两种完全不同的命运:一种是被 301 指向新页面,另一种是被直接删除返回 404。灰度如果只统计“有多少请求返回 404”,会把这两种情况混在一起,看不出例外。
更可操作的做法是按原始入口给链接分组,例如:
灰度发布后,分别观察这三组的去向。如果模板组已经改道、正文组仍然 404,说明替换规则只覆盖了模板层,没有覆盖内容层。这个差异就是全量发布时会被放大的例外。
假设某站点把旧栏目整体迁到新路径,规则是旧地址 301 到新地址。灰度只把 5% 的访问导向新版本,并且验证的是“新版本页面能否打开”。这一步通过,并不代表旧地址处理正确。
如果灰度没有同时请求旧地址,就不会发现:旧栏目下有一部分页面在迁移清单里被遗漏,仍返回 404;另一部分页面虽然 301 了,但目标地址又二次跳转,最终落到一个无关页面。全量发布后,这部分遗漏链接的暴露面从 5% 扩大到 100%,问题才集中出现。
这个例子的关键不是数字,而是比较方法:灰度阶段要按“旧地址 → 首次响应 → 最终落点”记录一条完整链路,而不是只看最终页面是否可访问。只有链路一致,灰度结论才能外推到全量。
最需要警惕的反例是:灰度环境与全量环境使用不同的链接生成逻辑。例如灰度版本由新模板渲染,全量版本仍由旧系统渲染,或者灰度只对新用户生效、老用户仍走旧路径。此时灰度里“死链接已被处理”的结论,对全量用户并不成立。
另一类失效条件是缓存与重定向规则分层。灰度可能命中了一套较新的重定向配置,而全量流量经过的边缘层或应用层仍保留旧规则。于是同一批死链接在灰度里被改道,在全量里继续 404。判断这一点不能只看一次请求结果,而要确认请求实际经过的层是否与全量一致。
还要注意:robots.txt 的抓取限制不等于可靠的索引移除,站点地图不保证收录。灰度里某条链接没有被抓取或没有出现在站点地图中,不能单独证明它已经被正确处理;它也可能只是暂时未被发现。请求量或抓取量归零同样不能单独证明处理正确,还可能由屏蔽、超时、路径变更或统计口径变化造成。
灰度跑完,不要直接进入全量,而是先产出一份例外清单:哪些旧链接在灰度中仍返回 404,哪些发生了非预期跳转,哪些跳转链路过长。对每条例外标注它来自模板、正文还是外部入口,并注明灰度与全量在该路径上的差异。
然后只做一件事:把例外清单里的链接按来源分组,先修模板层和导航层,再处理正文层和外部入口层。修完后重新跑一次同样口径的灰度,确认同一组链接的去向与全量预期一致。只有例外清单收敛到可接受范围,全量发布才不会把灰度没覆盖的链接问题一次性放大。