先给结论:多层缓存下同一内链目标出现多个版本,通常不是“缓存坏了”,而是各层缓存的键、失效范围和回源路径不一致。定位时不要逐层清缓存,而要先固定一个可复现的请求,记录每层返回的目标 URL 与响应头,再按“谁改了内容、谁没收到失效通知”这条线追下去。下面用一个假设情境串起整个过程。
假设某站把栏目页 A 的内链从 /old-path 改成 /new-path。改完后,编辑在后台预览看到新路径,运营在手机浏览器看到旧路径,开发用命令行请求看到新路径。三个人都认为自己看到的是“线上真实状态”,争论因此卡住。
这时不要先判断谁对。先做一件事:让三方各自提供完整的请求信息,包括请求的完整 URL、请求头里的缓存相关字段、返回的响应头、以及是否带查询参数。把这三组信息并排放在一起,分歧往往立刻变成一张可核对的表:请求路径不同、缓存层不同,或某一层根本没参与这次变更。
多层缓存常见的有浏览器缓存、CDN 边缘节点、反向代理缓存、应用层缓存。它们返回不同版本,可能的原因包括:
区分这些原因的关键证据是响应头。不同缓存层通常会留下自己的标识,例如缓存命中状态、缓存年龄、回源标记。把这些字段抄下来,比反复刷新页面更有用。如果某一层没有留下可识别标识,就把它列为“待确认层”,不要假设它没问题。
动作要具体:选一个受影响的内链页面,构造一个固定请求,例如不带查询参数、不带个性化 Cookie、使用同一网络出口。然后依次做三组对照:
如果源站和回源一致、正常域名不一致,问题在缓存层或缓存键。如果源站和回源也不一致,问题在应用或数据层,缓存只是把差异放大了。这个结果直接决定下一步找谁:前者找缓存配置负责人,后者找内容发布或数据同步负责人。
这里有一个容易踩的坑:不同搜索引擎对缓存和抓取的处理并不相同,缓存层返回旧版本,不等于搜索引擎一定抓到了旧版本,也不等于索引已经更新。抓取限制、站点地图和缓存状态都不能单独证明索引结果,需要分别核查。把“缓存返回旧版本”直接等同于“搜索结果显示旧版本”,会让排查方向跑偏。
当三方看到不同版本时,最有效的做法是建一个最小核对表,每行一个观察点,每列一个角色或一层缓存。字段可以包括:请求 URL、请求头关键字段、响应状态、返回的目标链接、缓存标识、观察时间、观察人。
这样做的好处是,争论从“我这边是新的”变成“这一层在什么条件下返回旧值”。一旦条件明确,就能判断影响范围:是只有带某个 Cookie 的请求受影响,还是所有请求都受影响;是只有某个地区节点受影响,还是全局受影响。影响范围决定了修复的紧急程度和验证方式。
验证修复时,不要只刷新原来那个页面。要用同一组固定请求重新跑一遍对照,确认每一层的返回都一致。如果只验证了浏览器,CDN 边缘节点可能仍然返回旧版本;如果只验证了一个节点,其他节点可能仍未失效。
清缓存是动作,不是诊断。只有在已经确认某一层返回旧版本、且该层缓存键和失效机制明确之后,清缓存才有意义。否则可能出现两种情况:一是清完暂时正常,过一段时间又出现不同版本,因为失效通知本身没配对;二是清了不该清的那层,把其他正常缓存一起打掉,反而增加回源压力。
更稳妥的顺序是:先固定请求、记录各层返回,再判断是缓存键问题、失效范围问题还是回源数据问题。如果是缓存键设计导致同一内容有多个副本,清缓存只能短期缓解,需要调整键规则或失效策略。如果是回源数据不同步,清缓存不会解决根本问题。
把排查结果写成可执行结论:哪一层、在什么条件下、返回了什么、由谁负责修、修完后用什么请求验证。这样内链建设方法中的一致性问题,才会从“大家看到的都不一样”变成“我们知道差异在哪一层、下一步改什么”。