蜘蛛再次访问一个已经抓过的 URL 时,请求头里常常会带上 If-Modified-Since 或 If-None-Match。这两个头的意思很直白:上次我拿到的是这个版本,如果现在还一样,就告诉我一声,不用把整页传回来。服务器判断内容没变,就会回 304 Not Modified。
304 是抓取过程中很常见的一种响应,但它经常被误读。它不是“蜘蛛没来”,也不是“蜘蛛放弃了这个页面”,只是这一趟没有传输正文。它节省的是传输和解析的消耗,页面在爬虫侧依然是被看过的。
304 发生在哪一步
一次典型的重复抓取大致是这样:
- 蜘蛛请求 URL,带上上次记录的修改时间或 ETag。
- 服务器拿当前内容去比对这两个值。
- 一致就返回 304,响应体为空;不一致就返回 200,重新传一遍完整页面。
所以 304 只代表“和上次相比没变化”,并不能说明页面质量、排名或者抓取频次有什么结论。
正确实现 304 需要什么
要让 304 判断准确,前提是服务器能分清“变了”和“没变”。常见做法有两种:
- Last-Modified / If-Modified-Since:基于最后修改时间。静态页面、图片、CSS 这类直接映射到文件的资源比较容易做准。
- ETag / If-None-Match:基于内容生成的标识,通常更精确,但要求同一份内容稳定生成同一个 ETag。
麻烦多半出在动态页面上。如果模板里嵌了当前时间、随机数、会话 ID,或者每次都算出不一样的 ETag,蜘蛛每次都会拿到 200,条件请求形同虚设。反过来,如果内容已经改了,但程序逻辑没有更新 Last-Modified,服务器仍然会回 304,蜘蛛就继续拿着旧版本。
304 的前提是服务器说真话。判断逻辑一旦有偏差,省下的那点带宽换来的可能是蜘蛛长期看不到更新。
几个容易被忽略的地方
反向代理与 CDN 这一层
如果 CDN 或反向代理缓存了 ETag,而源站内容已经更新,缓存层可能仍按旧标识回 304。排查这类问题,要分别看源站直连和经过 CDN 的响应头是否一致,单看一侧容易得出错误结论。
304 和抓取频率没有直接关系
有些运营者想通过频繁返回 304 来“减少蜘蛛访问”。实际效果有限,因为蜘蛛是否再来、间隔多长,取决于站点整体更新情况、链接变化、抓取预算等多个因素。把 304 当成频率开关,通常达不到预期。
空响应不代表可以忽略状态码
304 的响应体是空的。如果日志里只统计字节数或内容长度,很容易把这类请求当成异常。统计时应单独看状态码分布,区分 200、304、301、404 各自的比例。
怎么验证自己站点的 304 是否正确
- 用命令行工具带条件头请求页面:先记下一次响应里的 Last-Modified 或 ETag,再用它发起第二次请求,看是否返回 304。
- 改动页面内容后重复上述请求,确认返回的是 200 而不是 304。
- 在服务器日志里按状态码聚合,看静态资源和 HTML 的 304 比例是否合理。
- 对经过 CDN 的 URL,在源站和 CDN 侧各做一次对比。
小结
304 是抓取过程中的一个效率细节。做对了能减少无谓传输,做错了可能让蜘蛛长期停留在旧版本上。它替代不了内容更新、内链调整和 Sitemap 维护,但当你在排查“蜘蛛为什么没看到新内容”时,它是一个值得优先检查的具体项。