先固定一个可复现的URL,再用带随机查询串的请求绕过CDN和页面缓存,对比源站直出、插件缓存和CDN三层的响应头与正文哈希。如果只有带查询串的版本正确,问题几乎必然出在某一层缓存的键或失效规则,而不是数据库或主题代码。定位顺序应从最靠近源站的一层往外走,每层只改一个变量。
多层缓存指浏览器缓存、CDN边缘缓存、WordPress页面缓存插件、对象缓存(如Redis)以及PHP OPcache可能同时存在。它们返回不同版本时,典型表现是同一URL在不同网络、不同登录状态或不同时间看到不同内容。此时“全部清空”只能短暂掩盖问题,无法说明哪一层的键设计有缺陷。
建议按以下顺序取证据,每步只记录响应头和正文中一个稳定标记(例如页脚时间戳或某个自定义字段):
curl -I请求正常URL,记录Cache-Control、Age、X-Cache以及可能出现的插件缓存标识。?nocache=随机值,观察响应头是否变化、正文标记是否回退到最新版本。如果带查询串的请求始终正确,而正常URL间歇性返回旧内容,说明缓存键没有把某个影响输出的变量(登录态、Cookie、移动端标识、语言前缀)纳入。动作是把该变量加入缓存键或设为不缓存,然后重新请求正常URL验证。这一步的结果决定下一步是查CDN规则还是查插件配置。
面对多层返回不同版本,通常有两种做法,成立条件不同。
做法一:统一缩短TTL并全量清缓存。适合流量低、内容更新不频繁、以静态展示为主的站点。代价是源站压力上升,CDN命中率下降;如果对象缓存里存的是过期数据,清页面缓存并不能解决,仍需单独处理对象缓存。判断条件:如果清空后问题消失但几小时内重现,说明不是残留旧缓存,而是失效事件没有触发,应转向做法二。
做法二:分层设置缓存键与失效钩子。适合有登录用户、多语言、多货币或频繁局部更新的站点。代价是配置复杂度上升,键设计错误会导致缓存碎片化,命中率反而下降。判断条件:如果带查询串的版本正确、正常URL错误,且错误内容与某个Cookie或请求头相关,就应优先检查键,而不是继续缩短TTL。
一个假设例子:某站点在CDN层按完整URL缓存,但WordPress插件按“URL+登录状态”缓存。未登录访客先访问并写入CDN,随后编辑登录后看到的是插件生成的新版本,而CDN仍返回旧版本。此时把登录态加入CDN的Vary或缓存键可消除分歧;若只清CDN,编辑再次访问仍会重现。数字仅用于说明比较方法:假设旧版本Age为3600秒,新版本Age为0,两者并存即指向键不一致。
不要依赖肉眼刷新判断,浏览器可能命中本地缓存。用命令行或开发者工具的“禁用缓存”选项,分别记录四类请求的结果:正常URL、带随机查询串、带登录Cookie、指定不同User-Agent。对每个请求记录状态码、缓存相关响应头、正文中同一个标记值。
若源站直连也错误,先确认是否有多台应用服务器且各自本地缓存未同步。动作是暂时固定到单台源站请求,观察是否一致;如果一致,说明多机缓存同步是根因,下一步应改为共享对象缓存或统一失效广播。
返回不同版本有时不是键的问题,而是更新后失效事件没有到达所有层。常见原因是插件只清理自身缓存,未通知CDN;或CDN的缓存标签与插件使用的标签不一致。验证方法是发布一次可观察的更改(例如修改某页面标题),记录各层何时更新。
如果CDN在TTL到期后才更新,说明主动失效未生效;如果对象缓存立即更新而页面缓存未更新,说明失效钩子只覆盖了一层。此时应检查各层是否在同一个更新动作中依次调用清理,而不是继续调整TTL。需要说明的是,抓取量或请求量归零不能单独证明缓存处理正确,它也可能是流量下降、robots限制或监控缺失造成的。
针对手中这个页面,可按以下顺序落地:先固定测试URL和标记值,再分别请求四种变体并记录响应头;根据对照结果只修改一层配置;修改后重复同一组请求,确认正常URL与带查询串版本返回同一标记;最后发布一次真实更新,验证失效链路是否覆盖所有层。每一步的结果决定下一步改哪一层,避免同时改动CDN、插件和对象缓存而无法归因。
如果站点使用HTTPS,它只保证传输加密,不保证缓存内容一致或安全无漏洞;不同CDN和缓存插件对Vary、缓存标签的支持需分别核查,不能假定行为相同。完成上述对照后,你应当能明确指出是键缺失、失效未广播还是源站多机不同步,并据此选择统一清缓存还是分层设键。