先做一次“同一请求的版本对账”:固定一个URL和一组请求头,分别记录浏览器、CDN、反向代理、应用缓存、对象存储或数据库查询缓存返回的内容标识(ETag、Last-Modified、Content-Length、Vary、Age、X-Cache 等),把不一致的层找出来,再决定是清哪一层、改哪条规则,还是让某层不再缓存。不要先全站刷新,那会把证据一起清掉。
选一个能稳定复现问题的页面或资源,不要选首页这种被多规则命中的对象。用同一台机器、同一网络、同一浏览器会话发起两次请求:第一次正常访问,第二次带强制刷新;再用命令行工具分别请求源站地址和CDN地址。每次记录响应头里的标识字段和响应体大小,写成一行对照表。
关键动作是给每个缓存层编号:L1 浏览器、L2 CDN 边缘、L3 反向代理或应用前置缓存、L4 应用内缓存(对象缓存、查询缓存)。同一个URL在四层各返回什么,列清楚之后,“哪层版本不同”就不再是感觉,而是可指认的对象。
假设一个例子:某CSS文件在浏览器显示旧样式,CDN响应头里 Age 很小、ETag 是新的,源站返回的 ETag 却是旧的。这说明CDN拿到的是更新后的副本,而源站上游还有一层没刷新。此时清CDN无效,下一步应去查反向代理或应用缓存。
响应内容不一致,不一定都是缓存返回了旧版本。常见成因有几类,判断依据不同:
Accept-Encoding、Cookie 或查询参数纳入键,另一层没有,于是同一URL命中不同副本。证据是带与不带某请求头时,返回体出现稳定差异。Cache-Control 的 max-age 或 s-maxage 不同,导致某层已过期、某层还在用。证据是同一时刻不同层的 Age 差距明显。这几类成因的处理动作完全不同。把“版本不同”直接当成“缓存没清干净”,很可能反复清理却一直复现。
验证顺序建议从离用户最近的一层往源站走,因为外层最容易观察,也最容易误判。
每一步的结论决定下一步:某层标识与源站一致,就可以跳过该层,不必清理;某层标识与源站不一致,才针对该层做失效或改键。这样能避免“全站刷新一遍,问题暂时消失但原因不明”的情况。
定位到具体层之后,处理动作要落到配置或流程上,而不是只做一次手动清理。常见对应关系:
处理完成后,用同一组请求再对账一次,确认各层标识一致。如果只是清理后暂时正常,但没有确认标识变化,问题可能在下一个TTL周期再次出现。
当页面内容本身依赖用户身份、地域或时间动态变化时,“所有层返回同一版本”并不是正确目标。此时需要先明确哪些差异是设计允许的,再判断异常。例如带登录态的页面,不同用户看到不同内容属于预期,不能用同一份响应体去要求各层完全一致。
另外,如果站点无法读取或控制某一层缓存(例如使用了不可配置的第三方缓存),就只能通过请求头、版本化文件名或缩短TTL来间接影响,无法直接定位该层内部状态。这种情况下,先确认自己能控制到哪一层,再决定是否值得继续排查更深的层。
最后,单次请求正常或单次清理后正常,都不能证明问题已解决。要在一个可观察周期内重复对账,确认各层标识持续一致,才能把这次定位结论当作可复用的处理依据。