先别急着清缓存。把争议落到一个具体页面或资源上,记录同一路径在不同角色手里返回的响应头、正文摘要和时间戳,再按“谁在什么条件下拿到哪一版”画出一条请求链。多数不一致不是缓存坏了,而是不同层对同一 URL 的键、过期规则和变体判断不同。
让每个角色提交同一份最小记录:请求的完整 URL、请求方法、请求时带的 Cookie 或语言头、响应状态码、Content-Length、正文前若干字节的哈希、Date 与 Age、ETag 或 Last-Modified、以及响应里出现的缓存标识字段。不要只发截图,截图无法确认时间顺序。
如果两方看到的内容不同,先比较 URL 是否逐字符一致,包括结尾斜杠、大小写、查询参数顺序。带 ?utm 或 ?v= 的地址常被缓存当作不同键,从而各自保存一份正文。这一步能排除相当一部分“版本冲突”其实只是地址不同。
把链路拆成浏览器、CDN 或反向代理、应用服务、对象存储或源站。用同一台机器、同一网络、同一请求头,依次直连每一层,记录上面那组字段。直连源站得到的版本是基准,但基准不等于正确版本,它只说明源站此刻输出什么。
Age 大于零且正文与源站不同,说明该层保存了旧副本;若 Age 为零仍不同,问题更可能在回源路径或变体选择。把每层结果记成一张时间线。只要有一层在两次相同请求间给出不同响应,且没有可解释的输入差异,它就该被列为嫌疑层,下一步只针对它做单变量复现。
第一类是缓存键设计问题:同一逻辑页面因查询参数、Cookie、语言头被拆成多个键,各键的过期时间不同,于是不同角色命中不同副本。第二类是过期与再验证问题:某层设置了较长的新鲜期,源站更新后它仍直接返回旧副本,直到过期才回源。第三类是发布流程问题:更新只推送到部分节点,或只替换了其中一份文件,导致同一路径在不同空间上内容不同。
区分方法很直接:如果清掉某一层缓存后所有角色立刻一致,成因偏向过期或新鲜期;如果清缓存后仍不一致,偏向缓存键或发布覆盖不全。注意,清缓存后一致不能单独证明该层配置正确,它也可能只是暂时把旧副本删掉了。
假设某页面在编辑侧显示新标题,在另一位同事侧显示旧标题。先取两边完整 URL,发现一边带追踪参数、一边不带。分别直连源站,两个 URL 都返回新标题,说明源站已更新。再请求不带参数地址经过代理,返回旧标题且 Age 明显大于零,带参数地址返回新标题且 Age 很小。此时合理判断是代理按不同键保存了两份副本,而不是源站没发布。
下一步动作是统一该页面的对外地址,去掉只用于统计的参数,或让代理在键计算时忽略这些参数。改完后重新按同一地址请求各层,确认正文哈希一致,再观察一个完整新鲜期,确认旧副本不再被命中。如果没有先做键的统一就反复清缓存,旧副本会再次生成,问题会周期性出现。
为每个争议页面建一条记录,字段固定为:基准地址、期望正文摘要、各层实测摘要、实测时间、使用的请求头、结论与负责人。结论只写“哪一层在什么条件下返回了哪一版”,不写“缓存有问题”这类无法核对的判断。
处理顺序建议是:先统一地址与请求头,再确认源站输出,然后逐层比对,最后才动缓存配置或发布流程。每次只改一个变量,改完立刻复测同一组记录。若某次请求量或抓取量归零,不要直接当成修复成功的证据,它也可能是监控中断、请求被拦截或统计口径变化,需要另找旁证。
涉及具体平台或服务商时,其缓存行为、清除入口和支持的指令字段要以该平台当期文档为准,不同平台并不通用。把这份记录交给开发、运维或代理服务方时,对方才能凭同一组事实判断该改键、改新鲜期,还是改发布覆盖范围,而不是各自凭印象清一遍缓存。