如何识别代理数据采集中的陈旧缓存响应
代理请求可以快速完成并返回 200,但其信息仍可能过旧,无法用于价格检查、库存监控、市场研究快照或本地化审计。轮换出口 IP 也不保证获得新表示:浏览器缓存、共享中间层、CDN、Service Worker、应用缓存和源站本身都可能复用数据。

正确问题不是“是否使用了缓存”。缓存通常正常且合理。真正的问题是:“响应是否满足本任务的新鲜度契约,以及能否证明由哪一层提供?”
公开来源说明:RFC Editor,RFC 9111《HTTP Caching》,2022 年 6 月。
用业务语言定义新鲜度
请求前先写明最大可接受年龄:
| 工作流 | 新鲜度契约示例 |
|---|---|
| 市场研究目录 | 必须在计划采集窗口内观察 |
| 价格或库存检查 | 表示年龄不得超过批准阈值 |
| 广告或本地化 QA | 素材与落地状态适用于活动窗口 |
| 合规归档 | 保存指定 UTC 时间实际观察到的表示 |
| 静态参考数据 | 即使字节不变,也需验证器确认仍有效 |
不要设定一个全局阈值。季度目录的“新鲜”不适用于短时促销。将契约与结果一起保存,便于之后解释通过原因。
理解各响应头能证明什么
记录响应头,但不要把任何单个字段视为绝对事实:
Date表示源站声明的消息生成时间。Age在复用缓存响应时报告其在缓存中的估计时间。Cache-Control描述缓存与再验证指令。Expires可以定义过期时间。ETag与Last-Modified是条件请求可用的验证器。Vary指出哪些请求字段参与缓存选择。Warning或中间层专有诊断字段可补充上下文,但可移植逻辑不应依赖未公开的供应商字段。
时钟偏差会扭曲时间比较。时间戳使用同步 UTC,请求耗时使用单调时钟,详见代理时钟偏差指南。
缺少 Age 不证明响应直达源站;存在 Age 也不代表正文不可接受。所有证据都必须与任务契约比较。
建立受控样本
使用可自行更新的已授权端点,在正文中返回无敏感信息的版本标记,并支持 ETag、Last-Modified、Cache-Control、Date 及条件请求。
至少执行以下阶段:
- 发布版本 A,通过直连对照与每条代理线路获取。
- 在声明的新鲜期内重复请求,确认合理复用。
- A 仍在新鲜期时发布版本 B,记录业务契约是否允许继续使用 A。
- 等待进入必须验证的阶段后再请求。
- 使用版本 A 的验证器发送条件请求。
- 模拟已授权的源站故障,观察是否明确允许提供陈旧响应。
- 恢复源站并确认线路最终收敛到版本 B。
不要使用随机生产页面作为样本。内容若不可预测变化,就无法区分缓存行为与源站差异。
保存结果信封
每次尝试记录:
test_case_id
observed_at_utc
route_id
exit_region
session_id_hash
request_header_profile
final_status
redirect_chain_digest
date_header
age_seconds
cache_control
expires
etag_hash
last_modified
vary
content_type
body_byte_count
body_digest
semantic_version_marker
duration_ms
freshness_contract_seconds
freshness_result
验证器可能包含内部标识时应保存摘要。不得记录代理凭据、授权头、Cookie、令牌、个人数据或完整敏感正文。
使用请求头完整性测试证明对照和代理请求采用相同相关字段。如果 Accept-Language、编码偏好、Cookie 或授权信息不同,正文差异可能是正确变体而非陈旧数据。
重试前先分类
使用明确状态:
- 新鲜且等价: 满足契约,版本或验证器符合预期,业务语义正确。
- 新鲜但属于变体: 满足契约,但因
Vary、地区、账号或实验维度而不同。 - 陈旧但允许: 超过正常新鲜期,但响应策略明确允许且任务可以接受。
- 陈旧且不可接受: 超出业务契约,或必须验证后仍持续返回旧内容。
- 源站已更新、缓存未收敛: 受控源站为 B,某条线路在策略外仍返回 A。
- 无法判断: 缺少时钟、响应头、正文或对照证据。
- 内容无效: 拦截页、登录外壳、残缺正文或错误模式;新鲜度无法补救。
不要把所有摘要差异标记为“新鲜”。不同的错误页不是有效新表示。传输成功后仍需检查必需字段、语言、记录数和版本标记。
再验证时保留首次证据
先执行原始请求并保存结果。随后在源站契约允许时,使用已记录验证器发起受控再验证。304 Not Modified 可以确认已存储表示仍有效,但不会提供新正文。
测试需要强制验证时可使用 Cache-Control: no-cache,不要把它与 no-store 混淆,也不要默认添加随机查询参数。缓存破坏参数可能改变应用资源、服务器行为、分析或签名要求,而且测试的是另一个缓存键。
若必须测试唯一 URL,只能使用自有或已授权受控端点,并将其标记为独立实验。不得对第三方网站执行无边界的缓存破坏。
每次只改变一个维度
矩阵至少包括:
- 直连对照与代理线路;
- 各目标地区;
- 新连接与复用连接;
- 干净与有记录的浏览器配置;
- 普通获取与条件验证;
- 完全相同的 URL、方法、相关请求头和账号状态;
- 源站健康及已批准故障模拟。
同时改变出口 IP、Cookie、语言、浏览器版本、请求头和 URL 会破坏归因。代理连接池年龄测试可帮助分离连接复用与响应复用。
常见故障模式
旧正文相同,Age 持续增加
在响应或业务新鲜期到期前可能完全合理。超出策略后,保存缓存指令、验证器行为、线路和正文摘要再升级处理。
旧正文相同,但没有 Age
检查浏览器缓存、Service Worker、应用响应和源站。没有 Age 不等于直达源站。
轮换 IP 后正文不同
确认语言、账号状态、实验分组和 Vary 输入。新正文可能只是地区变体,而不是更新的表示。
返回 304,但业务数据仍显得陈旧
验证器可能正确确认表示未变化,而源站应用本身的数据已经陈旧。缓存验证证明的是相对于验证器的表示状态,不是业务事实。
把快速响应当作缓存命中
延迟不是可靠的缓存证据。附近源站可以很快,拥塞缓存也可能很慢。应使用响应头、验证器、受控版本变化和正文摘要。
操作检查清单
- 为每项任务定义新鲜度阈值。
- 记录准确 URL、方法、请求头、线路、地区及客户端构建。
- 保存
Date、Age、Cache-Control、Expires、验证器和Vary。 - 对正文计算摘要并验证业务语义。
- 与受控直连线路对比。
- 在再验证或重试前保存首次结果。
- 每次只改变一个维度。
- 区分合理变体与陈旧内容。
- 避免无边界查询参数缓存破坏。
- 脱敏凭据、标识符、Cookie 和敏感正文。
- 针对契约失败告警,而不是针对使用缓存告警。
常见问题
轮换住宅代理是否保证内容最新?
不保证。轮换改变网络出口,但浏览器、中间层、CDN、Service Worker、应用或源站缓存仍可能复用表示,也可能只产生不同地区变体。
Age: 0 能否证明源站生成了新正文?
不能。它只是一个缓存信号。还需结合验证器、受控版本标记、正文摘要和直连对比。
每个采集请求都应使用 no-cache 吗?
不应。这会增加源站负载并失去合理性能收益。只在业务需要验证且目标允许时使用,并与已记录的新鲜度契约一致。
陈旧响应是否可能被接受?
可以,前提是 HTTP 策略允许且业务契约接受,例如已批准源站故障期间的非关键参考数据。必须明确标记,不能简单称为新鲜。
合规说明
只测试你获准使用的端点、账号、数据集和代理基础设施。遵守缓存指令、访问控制、合同、隐私、版权、适用的 robots 规则和速率限制。控制样本流量,不得利用缓存测试绕过限制或迫使源站承受过量负载。