搜索抓取

304 与条件请求:让蜘蛛少下一遍没变的页面

蜘蛛每次回访都要重新下载整个页面,哪怕内容一个字没改。条件请求通过 Last-Modified 和 ETag 让服务器回一个 304,省下带宽和解析成本。本文讲清它能省什么、不能省什么,常见的配置坑在哪里,以及和 Sitemap lastmod 怎么对齐。

搜索抓取

304 与条件请求:让蜘蛛少下一遍没变的页面

很多人盯着抓取次数,却忽略了一个更细的消耗:蜘蛛每次来都要把整个页面重新下载一遍,即使这一页从上周到现在一个字都没改。条件请求就是用来解决这种浪费的——它让服务器有机会告诉蜘蛛“内容没变,别下了”,只回一个 304 状态码。

条件请求在做什么

蜘蛛第一次抓取某个 URL 时,服务器除了返回页面,还会带上一两个版本标记:Last-Modified(最后修改时间)和 ETag(内容指纹)。下次蜘蛛再来,会在请求头里带上这两个字段对应的条件:

  • If-Modified-Since:如果页面在这个时间之后没改过,就别返回正文。
  • If-None-Match:如果 ETag 还对得上,同样别返回正文。

服务器判断之后,若内容确实没变,就回一个 304 Not Modified,不带正文。蜘蛛由此知道:页面还在,内容没变,不需要重新解析和走索引流程。

它能省什么,不能省什么

先把边界说清楚,避免期待错位:

  • 省的是传输和解析:少下几十到几百 KB 的 HTML,少一次 DOM 解析,服务器带宽和响应耗时也轻一点。
  • 不省请求本身:蜘蛛仍然会访问这个 URL,304 只是让这一次访问少传内容。所以它替代不了“减少无价值 URL”那部分工作。
304 是降本,不是节流。真正吃掉抓取机会的,是那些本来就不值得抓的 URL,而不是“值得抓但没变”的 URL。

常见的配置坑

一、时间戳每次都变

有些 CMS 每次渲染页面都把 Last-Modified 设成当前时间。蜘蛛下次带着这个时间再来问,服务器自然判定“已修改”,又返回 200 和完整正文,条件请求等于失效。

二、ETag 算法不稳定

如果 ETag 按服务节点、按请求时间或按随机值生成,同一个页面在不同机器、不同请求下拿到的 ETag 各不相同,比对永远不匹配。多机房、多实例的站点尤其容易踩这个坑。

三、正文变了却回 304

这比配置失效更麻烦。内容更新了但版本标记没更新,蜘蛛会以为页面还是老样子,新内容可能很久才被重新处理。更新页面时要确保 Last-Modified 和 ETag 一并刷新,做不到就干脆别做条件请求。

四、缓存层改写了响应

CDN 或反向代理可能自行处理条件请求头,也可能把源站的 304 转成 200。排查时最好分别看源站和 CDN 返回的状态码与响应头,不要只盯着浏览器里看到的结果。

和 Sitemap 的 lastmod 对不上怎么办

Sitemap 里的 lastmod 和 HTTP 头里的 Last-Modified 是两套东西,但它们讲的是同一个故事。如果 Sitemap 说今天更新过,实际响应头却显示两个月前,蜘蛛对这两个信号的信任都会打折。合理做法是让两者由同一份数据源生成:内容真正被编辑时才更新字段,不要用发布时间、上线时间或自动任务时间凑数。

哪些页面值得配

  • 内容型页面,单页体积大、更新频率低,收益最明显。
  • 列表页和分类页,只要排序规则和内容稳定,也可以做。
  • 频繁变动、每次请求都不同的页面(实时数据、个性化推荐),不适合靠条件请求省流量,重点应放在是否值得让蜘蛛抓。

一次简单的自查验证

  1. 用同样的请求头连续请求同一个 URL 两次,第二次带上第一次返回的 ETag 或 Last-Modified。
  2. 看第二次的状态码是不是 304,正文是不是空的。
  3. 改一段正文再请求一次,确认状态码回到 200,并且版本标记随之变化。

这三步能覆盖大部分配置问题。做完之后,蜘蛛再访问这些稳定页面时,消耗的带宽和解析成本会降下来,更完整的抓取能力就能留给真正在变的页面。