先给结论:当CDN、反向代理、应用缓存和浏览器缓存对同一URL给出不同响应时,不要先怀疑404规则本身,而要把“谁返回了哪个版本”变成可核对的证据。具体做法是固定一个请求样本,逐层绕过缓存取回状态码、响应头和响应体指纹,再判断分歧来自缓存键、缓存层级还是源站。只有把分歧落到某一层,后续的404错误排查才不会在多人之间反复打转。
矛盾现象通常是这样:运维在服务器上访问某个URL得到200,SEO同事在浏览器里看到404,而监控探针又报告301。三个角色都没有说谎,但他们看到的很可能不是同一层缓存的输出。此时有两种解释成立。
第一种解释是缓存分层。CDN边缘节点、反向代理、应用内缓存各自保存了不同时间点的响应。某一层在源站改版前缓存了404,另一层在改版后缓存了200,于是不同入口拿到不同版本。第二种解释是缓存键错位。缓存系统按主机名、协议、查询串、Cookie或Accept头等要素拼缓存键。如果两层对键的组成理解不同,同一个URL会被拆成多个缓存条目,各自缓存了不同响应。
这两种解释都会表现为“同一URL不同结果”,但处理方向完全不同:分层问题要按层刷新,键错位问题要统一缓存键定义。先别急着清缓存,先取证。
能区分两种解释的证据,核心是“控制变量后看响应是否收敛”。可以按下面的顺序做一次核对。
Age、Cache-Control、X-Cache、Via这类字段,以及响应体长度或哈希。这里有一个假设例子:某URL在CDN返回404且Age较大,在反向代理返回200且Age接近0,源站返回200。这组证据指向CDN边缘缓存了旧404,而不是源站规则出错。下一步应是针对该边缘节点刷新或等待其过期,而不是修改站点404模板。
多个角色对同一事实理解不同,往往是因为各自描述的是不同层的结果。可以把分歧拆成一张核对表,让每个人填写自己观察到的层、请求方式、状态码和响应头关键字段。这样做的实际动作是:把“我这边是404”改写成“我在CDN边缘、带Cookie请求、状态码404、Age为若干秒”。
核对表填完后,通常能直接看出分歧集中在哪一层。如果同一层同一请求方式仍给出不同结果,再检查是否存在多台源站、灰度发布或地域节点差异。这个动作的结果会决定下一步:证据收敛到某一层,就修那一层;证据仍分散,就先统一缓存键和观察口径,再谈修复。
第一,把请求量或抓取量归零当作处理正确的证明。某个URL的访问量下降,可能只是监控探针改了路径、日志采样调整或缓存命中率上升,不能单独说明404已经修好。要回到状态码和响应体本身。
第二,用robots.txt限制抓取来代替移除。robots.txt只约束爬虫行为,不等于可靠的索引移除,也不解决缓存层返回404的问题。它和缓存一致性是两个层面的事。
第三,看到HTTPS就认为响应可信。HTTPS保证传输加密,不保证缓存层内容是最新版本,也不保证源站逻辑正确。排查404一致性时,协议安全与内容一致性要分开看。
修复动作执行后,不要只在一个入口验证。用最初那组固定样本,重新从CDN、反向代理、源站三个位置各取一次状态码和响应头,确认它们收敛到同一版本。如果仍不一致,说明还有一层缓存没有覆盖到,或者缓存键定义尚未统一。把这个回归结果记录下来,它就成为下一次404错误排查时判断“是旧问题复发还是新问题”的基线。
整个流程的要点是:先固定请求样本,再按层取证,用响应头和时间字段区分分层与键错位,最后把角色间的口头分歧转成可核对的表格。做到这一步,多层缓存带来的404版本不一致就不再是玄学,而是一个可以逐层定位的具体问题。