灰度阶段只放行一组目录时,你验证的其实是“这组目录在旧规则下能否通过”,而不是“全量发布后所有目录都能通过”。全量发布把其余目录一起纳入,旧规则中原本被更宽泛的禁止规则掩盖的例外就会生效,于是出现灰度正常、全量异常的落差。判断该保留、改写还是退出这些例外,取决于例外是真实业务需求,还是历史遗留的补丁。
灰度通常选一条最干净的路径:只放开少量目录,其余仍保持原来的禁止状态。此时请求能返回内容,只能说明这组目录没有被现有规则挡住,不能说明全量发布后新增的目录不会被别的规则挡住。robots.txt 的匹配是按爬虫声明的 User-agent 分组、再按路径前缀或通配逐条判断的,先命中的规则往往决定结果。灰度目录恰好不落在那些例外路径上,例外就不会被触发。
一个可区分的证据是:把灰度期间实际返回内容的 URL 逐条列出,再对照全量发布后计划放开的 URL 列表,看两者是否落在同一批路径前缀下。如果灰度 URL 集中在 /a/,而全量还要放开 /a/private/,那么只要存在一条针对 /a/private/ 的禁止规则,灰度就永远测不到它。这不是抓取量归零或日志异常能单独证明的问题,日志干净只说明灰度目录没被挡,不说明例外不存在。
如果例外规则对应的是确实不该被抓取的路径,例如带会话参数的动态入口、内部检索结果页、需要登录才能产生内容的接口,那么灰度暴露例外反而是好事,应当保留。保留的前提是你能指出这条例外的业务来源,而不是“以前加的,没人敢删”。
保留的代价是全量发布时必须维护两套认知:一套是面向搜索引擎的放行范围,一套是例外清单。例外越多,后续每次放行都要重新核对一次,遗漏的概率随例外数量上升。若例外超过你能逐条解释的数量,保留就不再是稳妥,而是把风险往后拖。
很多例外写得过宽,用一条禁止规则盖住整个目录,只为了保护其中一小部分路径。这时改写比保留更合适:把禁止范围收窄到真正需要保护的路径,让灰度没覆盖到的正常目录在全量发布时也能被抓取。改写需要先确认目标路径是否真的能被收窄,例如把 Disallow: /a/private/ 收窄为只禁止其中带特定参数的入口。
改写的实际动作是先复制当前规则,再在副本上收窄,然后对比新旧规则对同一批 URL 的判断结果。如果收窄后原本被挡的正常路径变为可抓取,而需要保护的路径仍被挡,改写成立;如果收窄后保护路径也漏了出去,说明这条例外依赖的是整段禁止,不能只靠路径收窄解决,应回到保留或换用其他手段。
当例外既说不清来源,又无法用一组 URL 验证它是否仍然必要,退出比继续维护更合理。退出的动作不是直接删除,而是先把例外单独隔离到一份临时规则中,观察一段时间内是否有原本依赖它的路径出现异常抓取或异常暴露。这里要说明一个常被误用的推论:抓取量下降、某路径请求归零,并不能单独证明例外该保留,也可能是抓取预算转移、页面本身失效或站点地图未更新所致。
退出的代价是可能重新暴露本不该被抓取的路径。若这些路径涉及隐私或重复内容,退出前应确认有 robots.txt 之外的替代控制手段,因为抓取限制并不等于可靠的索引移除,被禁止抓取的 URL 仍可能因外部链接出现在结果中。
假设灰度只放行了 /docs/,全量还要放行 /docs/archive/,而现有规则里有一条 Disallow: /docs/archive/。可以这样比较:
/docs/archive/ 确实不该被抓取。代价是全量发布时该目录继续不可抓取,若业务其实需要它,损失的是这部分内容的可发现性。/docs/archive/tmp/ 需要保护。动作是把禁止范围收窄到该子路径,结果是 /docs/archive/ 其余部分可被抓取,同时 tmp 仍被挡。三种选择的共同前提是:你能列出全量发布后计划放开的完整 URL 列表,并逐条判断它落在哪条规则下。做不到这一点,灰度就只是验证了一条路径,而不是验证了发布范围。下一步应当先补全这份列表,再决定保留、改写还是退出,而不是在全量发布后靠抓取日志反推哪里出了问题。