搜索抓取

304 与条件请求:蜘蛛重复访问同一 URL 时,服务器该回什么

蜘蛛对站点的大部分访问都是重复回访。服务器把 Last-Modified、ETag 与条件请求配合好,可以稳定返回 304,让重复抓取更省资源;配合不好,每次请求都回 200,还会让更新信号失真。本文讲清条件请求的工作方式、三类常见配置问题,以及一套可执行的自查步骤。

搜索抓取

304 与条件请求:蜘蛛重复访问同一 URL 时,服务器该回什么

蜘蛛对站点的大部分访问,不是第一次发现新 URL,而是回来确认旧 URL 有没有变化。一个持续更新的栏目页可能一天被访问多次,一篇半年前的文章也可能隔几周被回访。这些重复访问里,服务器怎么回应,会直接影响蜘蛛对页面更新频率的判断,也会影响它对整个站点的抓取节奏。

重复访问是常态,不是异常

很多人看抓取日志时,注意力都放在“新 URL 有没有被发现”,忽略了另一条线:同一个 URL 被反复请求。蜘蛛需要维护一份本地副本,用来判断页面是否变化、要不要更新。它没有别的办法,只能定期回来问一次。所以日志里大量重复的 GET 请求本身是正常现象,关键在服务器给出的答案是否有效。

条件请求:蜘蛛带着上次的版本信息来问

HTTP 提供了协商机制。蜘蛛第一次抓取某页时,服务器通常会在响应里给出 Last-ModifiedETag。下次再来,蜘蛛可以把它们分别放进请求头:If-Modified-SinceIf-None-Match。服务器比对之后,如果内容没变,返回 304 Not Modified,不带正文;如果变了,返回 200 和完整内容。这套机制叫条件请求。

304 省掉的不只是流量

  • 正文体积:一个几十 KB 的 HTML 不必重复传输,出口带宽压力小很多。
  • 蜘蛛侧的解析成本:不用重新解析、对比、入库。
  • 抓取节奏:重复 URL 占用的时间少一点,分配给新 URL 和深层页面的机会就多一点。

需要说明的是,304 并不等于这个 URL 被重新收录或排名发生变化,它只是告诉蜘蛛“内容还是你手里那份”。收录与展示是另一套流程在决定的事。

三种常见的配置坑

Last-Modified 每次请求都变

一些 CMS、模板引擎或中间件会在渲染时把 Last-Modified 设成当前时间。结果蜘蛛每次都带着上次的时间来,服务器每次都判定“已经更新”,永远返回 200。更麻烦的是,页面明明没改,蜘蛛却把它记录成刚刚更新过,长期如此容易让更新信号失真。

ETag 里混入了机器变量

某些服务器生成的 ETag 包含进程号、请求时间戳或节点标识。同一份内容,在多台后端或不同 CDN 边缘节点上算出的值不一致,蜘蛛带来的 If-None-Match 自然匹配不上,于是每次都拿到 200。如果站点同时用了多机部署和缓存层,这个问题出现的概率会明显上升。

动态页面完全忽略条件头

有些程序对静态资源做了条件请求处理,对列表页、详情页这类动态输出则直接跳过。而这类页面往往恰好是蜘蛛最常回访的,忽略条件头相当于把最该节省的地方放过了。

自查可以这样做

  1. 挑一个近期没有改动的页面,请求一次,记录响应里的 Last-Modified 和 ETag。
  2. 把这两个值分别放进 If-Modified-Since 和 If-None-Match,再请求一次,观察是否返回 304。
  3. 间隔几分钟重复第二步。如果偶尔返回 200,多半是时间戳或 ETag 不稳定。
  4. 对同一 URL 分别走直连源站和 CDN,比较两次拿到的 ETag 是否一致。
  5. 回到服务端日志,确认 304 在重复请求里占多大比例。比例很低,就值得往上查一层。

别把 304 当成偷懒手段

还有一类反向的做法:内容明明变了,却因为缓存或程序判断错误,一直返回 304。蜘蛛会继续使用旧副本,页面上新的标题、价格、库存都不会被看到。条件请求的前提是判断准确,而不是尽量少返回 200。

分清楚两种情况:内容确实没变,可以放心回 304;不确定有没有变,或者页面本来就是实时输出的,就老老实实回 200。前者省资源,后者省麻烦。

回到抓取的整体视角,服务器稳定性、响应头和状态码,是蜘蛛理解一个站点的底层语言。URL 发现决定了蜘蛛能走到哪里,而重复访问时的回应质量,决定了它愿不愿意经常回来。