先给结论:当错误页面返回 200 时,不能只看状态码判断对错,而要把“这个 URL 实际返回了什么内容、这个内容对应哪种状态、谁在依赖哪个信号”分别记录下来,再决定是改应用、改网关还是改监控。核对的核心是同一 URL 在三种视角下是否一致:浏览器看到的正文、HTTP 响应头里的状态码、以及站内链接和站点地图把它当成什么。
多个角色对同一页面有不同理解,通常是因为各自看到的信号不同。开发看的是应用日志里的异常,运维看的是网关返回码,编辑看的是页面上有没有“内容不存在”的文字,监控看的是状态码统计。要推进,先取一条真实请求作为核对对象,而不是先争论谁对。
用命令行取一次完整响应,把状态行、关键响应头和正文前若干行一起保存:
curl -sS -D headers.txt -o body.html "https://example.com/一个不存在的路径"
动作的结果决定下一步:如果状态行是 200 而正文是“页面不存在”,说明应用在渲染错误页时没有设置状态码,问题在应用层;如果状态行是 404 但正文是正常商品页,说明路由或缓存把请求映射错了,问题在路由或缓存层。两种情况后续改动的位置完全不同。
一致性核对要同时看两个方向,不能只查 200 错误页这一种。
判断依据不是页面好不好看,而是正文里的语义与状态码的语义是否指向同一件事。标题、主段落、是否包含返回首页或搜索入口,这些是内容侧的判断材料;状态码、Cache-Control、X-Robots-Tag 是响应侧的判断材料。两侧都取到,才谈得上一致。
内容和状态一致之后,还要看这个 URL 被怎样对待。站内链接指向它、站点地图列出它、robots.txt 允许抓取它,这三件事彼此独立,不能互相替代。
这一步的实际动作是给每个 URL 打两个标记:内容是否有效、状态码是否匹配。两个标记不一致的条目进入修复清单,一致的条目不再重复讨论。修复后重新取一次响应,对比状态行和正文是否同时变化,而不是只确认其中一个变了。
假设某站商品下架后,访问旧链接返回 200,正文显示“该商品已下架”,同时页面底部仍有加入购物车按钮。可以这样核对:先取响应头和正文,确认状态行是 200;再确认正文中是否存在有效商品信息,结论是没有;然后检查该 URL 是否仍在站点地图和分类页链接中。若两者都有,处理顺序是先让应用对该类请求返回 410 或 404,再清理链接和站点地图条目,最后重新取一次响应验证状态与内容同时改变。这里的数字和站点都是假设,用于说明比较方法,不代表任何真实站点的表现。
如果监控、日志告警和报表都依赖状态码,那么修复重点是把状态码改成与内容一致;如果下游系统依赖页面正文里的字段,那么即使状态码正确,也要确认错误页不会输出这些字段。两种取舍成立的条件不同:前者要求应用层能在渲染错误页时设置状态码,后者要求模板层能把错误页与正常页的字段输出分开。先确认依赖关系,再决定改应用、改网关还是改模板,可以避免改完一处后另一处仍然对不上。