先给结论:当同一份 robots.txt 经多层缓存返回不同版本时,问题通常不在 robots.txt 本身,而在“哪一层缓存保留了什么副本、以什么键区分副本”。定位顺序应该是先确定各层返回的字节是否相同,再确定差异发生在哪一跳,最后才判断这条差异会不会真正影响抓取。下面用一个假设情境把决策过程走一遍。
假设某站点把 robots.txt 放在 CDN 后面,源站前面还有一层反向代理。运维在三个位置分别取同一路径:源站文件、反向代理响应、CDN 边缘响应。结果源站是 Disallow 某目录,反向代理返回的是上一版 Allow,CDN 边缘返回的又是更早的版本。此时如果直接去改 robots.txt 内容,很可能改完仍然三处不一致,因为真正没对齐的是缓存键和失效范围。
这个情境的关键条件是:三层都参与缓存,且各层的缓存键组成不同。只要有一层把 Host、协议、查询串或 Vary 纳入键的方式与相邻层不同,同一逻辑资源就会被拆成多个副本,后续更新只覆盖其中一部分。
在判断“缓存返回不同版本”之前,要先确认看到的是同一对象。常见干扰有三种:请求带了不同的查询串、请求走了不同协议或主机名、请求命中了不同机房节点。这三种情况下拿到的本来就是不同缓存键对应的副本,属于观察方式造成的差异,不是缓存一致性问题。
可执行的动作是:用同一路径、同一主机名、同一协议、不带查询串的方式,在尽可能短的时间窗内分别向源站、反向代理、CDN 边缘发起请求,并记录响应中的缓存状态字段和内容摘要。结果如何影响下一步:如果三处摘要一致,问题不在缓存一致性,应转向别处;如果不一致,才进入分层排查。
多层缓存的不一致,差异一定出现在某一跳的边界上。可以按下面的顺序逐跳比对:
每比对一跳,只问一个问题:这一跳两侧的字节是否相同。相同就继续往下一跳,不同就把这一跳当作差异来源。这样做的价值在于,它把“缓存不一致”这个笼统现象压缩成一个具体边界,避免在无关层反复刷新。
即使确认了某一跳返回旧版本,也不能直接推断抓取会出问题。robots.txt 的抓取限制不等于可靠的索引移除,反过来,缓存返回旧版本也不等于旧规则一定仍在对抓取生效。需要分别核查两件事:
如果旧副本与当前期望规则只在无关目录上有差异,影响可能有限;如果差异恰好落在需要放行或需要限制的目录上,才需要优先处理。这里的判断依据是规则差异的位置,而不是副本新旧本身。
假设排查发现差异集中在反向代理层,且该层的缓存键没有纳入协议。可以先只对这一层做一次受控刷新,然后立刻按第一步的取数方式重新比对三处响应。结果如何影响下一步:如果三处恢复一致,说明差异来源就是这一层的缓存键或失效范围,后续应把缓存键规则固化;如果刷新后仍不一致,说明至少还有第二层参与,需要回到第二步继续逐跳定位,而不是重复刷新同一层。
需要提醒的是,请求量、抓取量或某类响应统计归零,不能单独证明处理正确。它们还可能受抓取节奏、站点整体变更、抓取方自身调度等因素影响。判断一致性是否恢复,应以同一取数方式下的字节比对为主,统计指标只作为辅助观察。
对 robots.txt 这类小文件,内容本身往往几分钟就能改完,真正耗时的是确认哪一层在返回旧副本。编写阶段的取舍因此可以更明确:如果站点有多层缓存,应在发布流程里固定“源站文件、反向代理、CDN 边缘”三处的比对动作,并把缓存键与失效范围写成可复核的配置说明。这样下次再出现不同版本时,排查起点就不是猜测,而是逐跳比对。
最后要分清边界:robots.txt 的抓取限制不等于可靠的索引移除,站点地图也不保证收录;不同抓取方对同一规则的支持情况需要分别核查。一致性排查解决的是“哪一份副本在被读取”,它不能替代对规则本身是否合适的判断。