内容相同的两个页面,如果响应头不同,对它们的判断会明显分叉:一个可能被当作正常缺失页处理,另一个可能被当作软404或异常响应处理。结论取决于状态码、内容长度、缓存头和抓取上下文是否互相矛盾。最容易被忽略的反例是:内容完全相同但一个返回404、另一个返回200,此时仅凭页面快照无法区分二者,必须回到响应头本身。
当页面正文一模一样时,判断URL有效性的依据不在页面里,而在响应头。若一个URL返回404,另一个返回200,前者表达的是“此地址没有对应资源”,后者表达的是“此地址存在资源”。即使两段正文都由同一模板渲染,结论也不能互换。这种情况常见于站点把缺失内容统一渲染成带导航、推荐位的页面,正文看起来有内容,但响应头已经给出否定信号。
因此,看到内容相同就推断“两者等价”是不成立的。响应头决定了资源是否存在,正文只决定用户看到什么。若正文相同而响应头不同,应优先相信状态码,再用其他头字段交叉验证。
两个响应即使当前正文一致,若Cache-Control、Expires或ETag不同,后续行为也可能分叉。一个允许长时间缓存,另一个要求每次回源,那么下一次请求时,用户或中间层拿到的内容可能已经不同。此时“内容相同”只是当前时刻的观察结果,不是稳定属性。
判断时可以先固定一个前提:假设两个URL当前返回的正文逐字节一致,仅缓存策略不同。那么对返回404的那个URL,若缓存策略是长缓存,后续修复后可能仍被旧响应覆盖;若缓存策略是禁止缓存,修复后的状态更容易被立即观察到。这个假设说明,缓存头差异影响的是“修复后能否被及时看到”,而不是“当前是否算404”。
动作上,可以先记录每个URL的完整响应头,再分别请求一次并对比。若缓存头不同,下一步应优先确认缓存层是否按URL分别存储,而不是继续比对页面正文。
当状态码是200,但Content-Length很小、Content-Type异常,或正文与站点其他正常页面高度相似时,容易被判断为软404。软404的本质是:响应头说“资源存在”,但实际内容表达“资源缺失”。如果两个URL正文相同,一个返回404,另一个返回200,那么返回200的那个更值得怀疑,因为它的状态码与内容语义不一致。
这里不能只凭一个信号下结论。内容长度相同、正文相同,但一个返回404、另一个返回200,至少存在两种合理解释:一是返回200的URL确实存在,只是内容恰好与缺失页模板相同;二是返回200的URL实际是软404,只是没有正确设置状态码。要区分二者,需要看该URL是否出现在站点地图、内部链接或抓取日志中,以及它是否被其他页面引用。若这些证据都指向“不应存在”,那么软404的判断更可靠。
同一个URL,直接请求和通过站内链接抓取,可能得到不同的响应头,例如重定向链、Vary或缓存命中差异。若两个页面正文相同但响应头不同,需要先确认它们是否处在同一抓取上下文:是否都经过同一CDN、是否都带相同请求头、是否都从同一入口进入。上下文不同,响应头差异可能只是路径差异,而不是页面本身差异。
动作上,可以固定请求方式,分别记录直接请求和带站内Referer请求的响应头。若结果不同,下一步应检查重定向和缓存规则,而不是修改页面内容。若结果相同,再回到状态码与内容语义是否一致的问题上。
面对内容相同但响应头不同的两个URL,建议按以下顺序处理:
Content-Type、Content-Length、Cache-Control、Location和Vary。执行完这四步后,下一步动作会变得明确:要么修正状态码,要么修正缓存策略,要么修正路由。若跳过响应头对照直接改页面内容,很可能把软404伪装成正常页,反而让后续判断更困难。最终要记住:内容相同只是表面,响应头不同意味着这两个URL在资源存在性、缓存行为和抓取路径上可能属于不同类别,判断必须分开做。