先说清楚:304 是“内容没变”的确认信号
当搜索蜘蛛再次请求一个入口页时,通常会带上 If-Modified-Since 或 If-None-Match 请求头。服务器判断页面和上次一样,就返回 304 Not Modified,不返回正文。
对蜘蛛来说,这等于确认“还是我上次拿到的那个版本”。它会继续沿用本地缓存里的那一次抓取结果,包括当时页面里发现的目标链接。
所以 304 本身不会让已经发现过的目标 URL “失效”,也不会因为这次请求而重新解析一遍新链接——因为根本没有新正文可解析。
那 304 什么时候会变成麻烦
关键不在状态码本身,而在于页面真的变了,服务器却说没变。常见场景有这几种:
- 入口页的链接列表会定期轮换,但页面 mtime 没动,或用的是统一的发布时间。
- ETag 被中间层写成了固定值,或者由几个字段拼出来、内容变化时它却不变。
- CDN 或反向代理自己缓存了 HTML,并按自己的规则返回 304,源站更新没透传。
- 入口页由模板渲染,模板改了但文件时间戳没变,条件请求判断失效。
一旦出现这种情况,蜘蛛拿到的永远是旧版本链接列表,新加进去的目标 URL 就一直等不到第一次被发现的机会。
日志里怎么判断是“正常 304”还是“卡住了”
- 按入口页 URL 聚合状态码,看它是不是长期只有 304、几乎没有新的 200。
- 抽查请求头,确认蜘蛛是否带上 If-Modified-Since / If-None-Match,以及服务器返回的 Last-Modified / ETag 是否和内容更新同步。
- 手动改一次入口页内容,然后带同样的条件请求头发一次请求。如果仍然返回 304,说明条件判断有问题。
- 对比目标 URL 的首次被抓时间与入口页最后一次 200 的时间。若目标 URL 首次抓取时间明显晚于链接上线时间,基本可以确认入口页在“假 304”。
几个实际的调整方向
- 入口页内容变化时,让 Last-Modified 或 ETag 真实变化,不要用硬编码时间或固定字符串。
- HTML 类的入口页,缓存 TTL 别设太长;链接列表更新频繁时更要注意。
- 确认 CDN 是否忽略了源站的缓存校验头,必要时让入口页回源校验。
- 304 虽然不传正文,但仍会消耗一次请求。入口页数量多的时候,无意义的条件请求同样占用抓取预算,不要靠它来“省抓取”。
- 如果你确实希望蜘蛛尽快看到新链接,让入口页在更新后正常返回 200,是最直接的做法。
顺带一提:304 和“新链接发现”是两件事
链接发现依赖的是蜘蛛真正拿到并解析过一次的页面正文。它能复用缓存,但不会凭空知道缓存里不存在的东西。把“蜘蛛来过”当成“链接已经被发现”,是这类问题里最常见的误判。
304 说的是“和上次一样”,不是“再抓一次”。入口页的链接列表在变,就不要再让它一直回 304。