当两个地址返回的 HTML 正文完全一样,而响应头不同时,最容易误判的是“收录状态”和“重复内容处理”。robots.txt 只约束抓取,不决定索引;真正影响判断的是响应头里的状态码、Content-Type、X-Robots-Tag、Vary 和缓存指令。若正文相同但一个返回 200 且带 X-Robots-Tag: noindex,另一个返回 200 且无该头,那么它们对索引的候选资格并不相同,不能因为正文一致就当成同一份可互换的页面。
第一种条件:两个地址都在 robots.txt 允许范围内,正文相同,差别只在响应头。此时要优先看状态码和 X-Robots-Tag,而不是看 robots.txt 是否放行。第二种条件:其中一个地址被 robots.txt 禁止抓取,另一个允许。此时即使正文相同,被禁止的那个地址也无法通过常规抓取读到 noindex,索引判断会变得更不可控。
选择依据可以压缩成一句话:如果响应头里出现 noindex、4xx 或 5xx,先按索引层处理;如果只是抓取被 robots.txt 挡住,先按抓取层处理。两者不能混为一谈,因为前者影响页面能否进入索引,后者只影响抓取器能否读取。
状态码不同是最直接的分叉。一个地址返回 200,另一个返回 301,正文相同也不代表它们等价:301 会把信号和用户导向目标地址,判断应围绕目标地址展开,而不是围绕原地址的正文。若返回 410,则即使正文相同,也应按已移除处理。
Content-Type 不同会改变解析方式。一个返回 text/html,另一个返回 application/octet-stream,后者通常不会被当作 HTML 页面处理,正文相同也没有意义。X-Robots-Tag 不同则直接改变索引指令:带 noindex 的响应头会抑制索引,不带的那份不会。Vary 头不同会影响缓存与内容协商判断,尤其在按 User-Agent 或 Accept 返回不同版本时,同一地址可能被不同抓取器看到不同结果。
这里有一个常见误判:把 robots.txt 里的 Disallow 当成移除手段。robots.txt 的抓取限制不等于可靠的索引移除;如果页面已被索引,仅靠 Disallow 通常无法让它退出索引,因为抓取器可能不再读取页面上的 noindex。正确动作是先用响应头确认页面当前返回的指令,再决定是改状态码、加 noindex,还是保留抓取允许以便读取移除信号。
假设有 A、B 两个地址,HTML 正文逐字相同。A 返回 200,无 X-Robots-Tag;B 返回 200,带 X-Robots-Tag: noindex。此时不能因为正文相同就认为两者索引状态一致。第一步动作:用抓取工具分别请求 A、B,记录状态码和完整响应头,而不是只看页面源码。结果会直接影响下一步:若 B 确实带 noindex,而业务上希望保留 B,就应移除该响应头;若希望 B 退出索引,则保留 noindex,并确认 A 是唯一规范版本。
第二步动作:检查 A、B 是否互相声明 canonical。如果 B 带 noindex 又声明 canonical 指向 A,两个信号可能冲突,需要按实际目标取舍。第三步动作:观察抓取日志中 A、B 的请求频率变化。请求量下降或归零不能单独证明处理正确,因为抓取预算调整、站点整体抓取减少、日志采样口径变化都可能造成同样现象。应结合响应头是否被正确返回、页面是否仍可被抓取来交叉判断。
如果两个地址分别属于不同搜索引擎且支持情况不同,必须分别核查,不能用一个引擎的响应头结果推断另一个。站点地图不保证收录,所以把两个地址都放进 sitemap 并不能解决响应头差异带来的索引分叉。HTTPS 不保证安全无漏洞或排名,因此响应头差异的判断不应被协议层结论替代。
还有一种例外:页面通过 JavaScript 在客户端改写 meta robots。此时响应头里的 X-Robots-Tag 与渲染后的 meta 指令可能不一致,判断应以实际可被抓取和渲染的结果为准。若 robots.txt 禁止了渲染所需资源,客户端指令可能根本不被执行,这又回到抓取层条件。
可执行的最小清单是:先记录每个地址的状态码、Content-Type、X-Robots-Tag、Vary;再确认 robots.txt 是否允许抓取该地址;然后检查 canonical 与 noindex 是否冲突;最后用日志验证请求变化,但不把请求量变化当成唯一证据。这样做的结果是,你能把“正文相同”这个表面事实,拆成抓取、索引、规范化三个独立判断,避免用同一套结论覆盖所有地址。