先不要急着改代码或删缓存。正确顺序是:固定一个不携带登录态、不随设备变化的基准请求,用它和差异请求逐项对照,确认差异来自响应头、Cookie、User-Agent、IP 归属还是服务端分流规则。只有找到可复现的触发条件,才谈得上保留、改写或退出某条处理路径。若差异只在个别样本成立、规模化后出现例外,说明你捕捉到的可能只是边缘条件,不能直接照搬成全站策略。
对照的前提是有一个稳定参照。用命令行工具发起请求,关闭 Cookie 和重定向跟随,只保留最基本的请求头,把完整响应头和正文开头若干字节保存下来。这个基准请求代表“无状态、无设备特征”的访问结果。
然后逐个变量制造差异:分别加上登录 Cookie、换一个 User-Agent、从不同出口 IP 发起、带上 Accept-Language。每次只改一个变量,记录响应状态码、Content-Type、Content-Length、缓存相关头以及正文是否变化。这样得到的是一组可复查的对照记录,而不是凭印象判断“手机和电脑看到的不一样”。
动作与结果的关系很直接:如果加上某个 Cookie 后正文改变,说明服务端按登录态分流;如果换 User-Agent 后只有样式或跳转改变,说明差异可能在展示层而非内容层。下一步该查什么,由这一步的响应头决定,而不是先入为主地怀疑缓存。
常见差异来源可以按可区分证据归类:
这里有个容易被忽略的边界:robots.txt 里禁止抓取某条路径,不等于该 URL 会从索引中移除;站点地图里列出 URL,也不保证会被收录。所以对照时不要把“抓取限制”当成“内容已处理”的证据,两者是不同层面的事。
保留适用于差异是刻意设计、且缓存与抓取能正确区分维度的场景。前提是 Vary 声明完整、各版本内容本身正确、并且你愿意为每个维度维护独立内容。如果维度组合爆炸,维护成本会迅速上升。
改写适用于差异并非本意、但底层内容其实相同的情况。例如同一份数据因模板分支渲染出不同结构,可以合并成一套输出,把设备差异交给前端处理。前提是你能确认业务逻辑不依赖服务端分流,改写后不会破坏登录、地区或语言相关的必要分支。
退出适用于差异由实验性规则、遗留配置或临时开关造成,且没有保留价值。退出前要先确认这条规则没有被其他路径引用,否则关闭后可能连带影响正常访问。退出动作完成后,用同一组基准请求复测,确认差异消失且基准结果未变。
假设你在少数几个 URL 上通过加 Cookie 复现了内容差异,于是推断全站都按登录态分流。这个推断不成立,因为个别样本可能命中了特定缓存节点、特定机房或特定规则分支。规模化后出现例外,恰恰说明触发条件比你以为的更窄。
这时应扩大采样:从不同栏目、不同层级、不同更新时间的 URL 中各取若干,重复同一组对照请求。如果差异只在某一类 URL 上出现,说明触发条件与内容类型或路径规则相关;如果差异随机出现,则更可能是缓存节点不一致或分流未收敛。
判断时要注意:请求量、抓取量或某项统计归零,不能单独证明处理正确。它也可能来自采样偏差、抓取预算变化、外部流量波动或统计口径调整。要结合响应头、正文对照和访问日志一起看,而不是只看一个数字。
一份可用的对照记录至少包含:请求时间、完整请求头、响应状态码、关键响应头、正文差异位置、以及这次差异对应的假设。记录的目的是让下一个人能复现你的观察,而不是只留下结论。
当差异被定位到具体层之后,动作才有依据:属于缓存键问题就调整 Vary 或缓存策略;属于分流规则问题就评估保留还是合并;属于遗留配置就安排退出并复测。每一步动作完成后,都用同一组基准请求验证结果,确认没有引入新的差异。这样处理下去,同一地址返回不同内容就不再是黑盒,而是一组可以被逐层拆开、逐项验证的条件。