搜索抓取

304、ETag 与 Last-Modified:缓存协商怎样影响蜘蛛的复查判断

搜索蜘蛛复查 URL 时常带条件请求头,服务器回 304 就跳过正文传输。这个机制本身没有问题,但 Last-Modified、ETag 与 CDN 缓存如果配错,可能出现页面已更新却长期返回 304,或者标识每次变化导致重复下载。本文梳理一次复查请求的完整过程、常见配置失误与自查思路。

搜索抓取

304、ETag 与 Last-Modified:缓存协商怎样影响蜘蛛的复查判断

蜘蛛的复查请求并不是每次都从零开始。多数搜索引擎蜘蛛再次访问同一个 URL 时,会带上条件请求头:If-Modified-Since(基于上次拿到的 Last-Modified)和 If-None-Match(基于上次拿到的 ETag)。服务器判断内容没变,就回一个 304 Not Modified,蜘蛛知道不用重新下载正文。这个过程看起来只是省流量,实际上会影响蜘蛛对你站点更新节奏的判断。

一次复查请求里的三段对话

第一次抓取:蜘蛛请求 URL,服务器返回 200,正文之外还带上 Last-Modified、ETag、Cache-Control 等响应头。第二次抓取:蜘蛛带上条件请求头。第三次判断:服务器返回 304 或 200。返回 304,蜘蛛通常把这次记为“未变化”;返回 200,蜘蛛拿到新的 HTML,再做解析、比对和后续处理。

问题往往出在第二步和第三步之间的不一致上:响应头里的时间或标识说“没变”,但页面其实已经改了;或者反过来,标识每次都变,蜘蛛每次都拿到完整正文。

容易踩的几种响应头配置

  • Last-Modified 被写死或提前。有些程序把该字段统一设成发布时间或站点部署时间,页面后来更新了,时间却没动,蜘蛛容易持续收到 304。
  • ETag 每次请求都不一样。部分服务器按内容哈希之外的规则生成 ETag,或多台后端之间不统一,同一页面每次都是新标识,条件请求永远命中不了 304。
  • Cache-Control 设得过长,又经过 CDN。缓存层压着旧 HTML,蜘蛛拿到的是旧版本,页面上的新链接自然也不会被及时看到。
  • 动态页面把 304 当默认响应。个别实现不校验请求头就回 304,蜘蛛会认为内容长期未变,复查节奏也可能被压低。

304 不等于“没来过”

要分清两件事:304 是内容层面的判断,抓取行为本身仍然发生了一次——蜘蛛发起了请求,占用了连接和服务端资源,只是在传输阶段省下正文。所以 304 比例高,一般说明缓存协商工作正常,而不是说蜘蛛不来了。真正需要警惕的是两种情况:页面已经更新但长期返回 304;以及本该稳定的页面频繁返回 200 且内容几乎一致,白白占用抓取额度。

自查建议

  1. 挑 10–20 个近期更新过的页面,用带条件请求头的工具各请求一次,记录状态码和响应头。
  2. 对比 Last-Modified 与页面实际最后编辑时间,看是否同步。
  3. 连续请求同一 URL 两次,确认 ETag 是否稳定,条件请求能否稳定返回 304。
  4. 绕开 CDN 直接请求源站一次,确认缓存层没有长期压住新版本。
  5. 在服务器日志里按状态码统计 304、200、5xx 的占比,重点看重要栏目页的分布。

和 Sitemap、内链的关系

Sitemap 里的 lastmod 是另一条独立线索,蜘蛛会参考它决定是否提前复查某个 URL,但它替代不了响应头。比较稳妥的做法是让三者保持一致:页面真实更新时间、Last-Modified、Sitemap lastmod 不要互相打架。内链同样如此,指向更新页面的链接如果一直挂在列表页靠后的位置,即使响应头正确,URL 被重新发现的时间也会被推迟。

缓存协商解决的是“要不要传正文”,抓取路径解决的是“要不要来这一趟”。两者是不同层面的问题,不要用 304 的比例去判断抓取是否健康。

最后提醒一句:不要为了让蜘蛛频繁回来,故意让每个页面每次都返回 200 和变化的 ETag。这种做法的代价是抓取额度和带宽,收益却很难验证。把响应头配准,让更新时间和内容真正对应,是更省事的做法。