搜索抓取

缓存头与 304:蜘蛛重复访问时,服务器该怎么回应

蜘蛛第二次、第三次访问同一个 URL 时,往往带着条件请求头。服务器返回全量内容还是 304,取决于 Last-Modified、ETag 与 Cache-Control 的设置。本文梳理这三个头各自管什么、CDN 边缘缓存如何影响蜘蛛看到的版本,以及日志与缓存记录该怎么并排核对。

搜索抓取

缓存头与 304:蜘蛛重复访问时,服务器该怎么回应

蜘蛛第一次抓走一个 URL 之后,通常还会回来。第二次、第三次它带着缓存校验信息来,服务器回什么,会直接影响抓取节奏和带宽消耗。这块内容在日志里不如 404、500 显眼,容易被忽略,但积累起来对抓取效率的影响并不小。

条件请求:蜘蛛不是每次都从零开始

支持条件请求的爬虫在重新抓取时,会带上 If-Modified-SinceIf-None-Match。服务器判断页面没有变化,就返回 304 并给出空响应体,蜘蛛据此知道内容照旧,可以复用已有版本。响应体变小,抓一个 URL 的成本降低,同样的抓取预算能走更多地址。

  • If-Modified-Since 依赖响应里给出的 Last-Modified 头
  • If-None-Match 依赖 ETag
  • 两者可以同时存在,服务器按自己的优先级判断,但结果要一致

三个头分别管什么

Cache-Control

它主要面向浏览器和中间缓存,蜘蛛本身对 max-age 的依赖有限,但 CDN 边缘节点会照它执行。如果把 HTML 设成很长的 max-age,边缘节点可能长期不回源,蜘蛛每次拿到的都是旧内容,更新传不出去。常见做法是 HTML 走短缓存或协商缓存,静态资源长缓存。

ETag

ETag 是资源版本的指纹。要保证同一份内容在不同节点上生成的 ETag 一致,否则请求在边缘节点之间切换时,可能被反复判定为已变更,回源和全量响应都会变多。有站点干脆用内容哈希而不是时间戳来生成。

Last-Modified

时间戳要真实反映内容变化。有些程序每次渲染都刷新这个值,蜘蛛每次访问都被判定页面更新,于是重复下载。页面实际没变的时候,把它稳定住。

304 是不是好事

一般情况下是的,但有两个前提。一是页面内容确实没变;二是 304 不会掩盖真实问题——比如某次模板报错,页面被降级成空壳,若仍返回 304,蜘蛛会继续认为旧版本有效。另一类情况是新页面刚上线,服务器错误地返回 304,蜘蛛可能延迟发现。核对时把 200 与 304 的比例放进更新时间线里看,比只看总量更有意义。

CDN 与回源

蜘蛛的出口 IP 分散,命中不同边缘节点时,看到的缓存状态可能不同。抓取日志和 CDN 日志要并排看:哪些请求命中边缘、哪些回源、回源后的状态码是什么。如果某类 URL 命中率极低,通常是缓存键设计的问题,常见原因是键里带了 Cookie 或跟踪参数,把同一份内容拆成了很多份。

  • 缓存键要不要包含查询参数,按参数是否影响内容决定
  • 不要给蜘蛛的 UA 单独开一条绕过缓存的规则,容易让缓存形同虚设
  • 回源频繁的 URL 类型,优先排查缓存键与 Vary 头
缓存策略的目标不是单纯省流量,而是让蜘蛛每次拿到准确的当前版本,并且不为没变化的内容重复付费。

核对顺序

  1. 在日志里筛出同一个 URL 的多次访问,观察响应码与响应体大小
  2. 抽样几个更新过的页面,确认 Last-Modified 与 ETag 随内容变化
  3. 检查 HTML 的 Cache-Control,避免过长的 max-age 卡住边缘节点
  4. 对比 CDN 命中与回源记录,找出反复回源的 URL 类型
  5. 手动发一次条件请求,确认内容未变时服务器返回 304

这些检查不需要一次做完。从访问量最高的一批 URL 开始,逐步往外扩,改动一次就回到日志里验证一次,比一次性推翻整套缓存配置稳妥得多。