很多站点排查抓取问题时只盯着状态码是不是 200,忽略了蜘蛛请求头里带的 If-Modified-Since 和 If-None-Match。这两个字段决定了服务器返回 304 还是完整正文,而 304 的占比,直接影响服务器压力和抓取节奏的观察结果。
条件请求是怎么来的
蜘蛛重复抓取一个已知 URL 时,往往会复用上一次拿到的缓存标识。上一次响应带了 Last-Modified,这次请求就会附带 If-Modified-Since;带了 ETag,就会附带 If-None-Match。服务器比对后如果判断内容没变,返回 304 Not Modified,不带响应体。这是标准的 HTTP 协商流程,不是蜘蛛在偷懒。
但要注意,304 依然是一次完整的请求往返。DNS、连接建立、请求头、响应头都要走完,省下的只是响应体传输和后续解析。所以别把 304 理解成“没有被抓取”,它只是少了正文。
Last-Modified 的常见坑
- 格式不规范:必须使用标准 HTTP 日期格式,输出时间戳或本地化写法时蜘蛛可能无法解析,条件请求会退化成每次全量抓取。
- 每次都刷新:动态页面把 Last-Modified 设成当前时间,等于告诉蜘蛛“每次都变了”,并不能换来更高的抓取频率,反而让修改时间失去参考价值。
- 时区错位:直接输出服务器本地时间,会让判断出的修改时刻偏早或偏晚,影响对更新节奏的理解。
ETag 的生成方式更关键
ETag 常见两类:一类基于内容摘要,内容不变值就不变;另一类是服务器默认按文件 inode、大小、修改时间拼出来的,多台后端机器之间天然不一致。如果站点走负载均衡或多个 CDN 节点,同一 URL 在不同节点返回不同 ETag,蜘蛛每次带来的条件都匹配不上,于是持续收到 200 和完整正文。
核对时不要只看单台机器。用不同出口 IP 或不同节点请求同一 URL,比较 ETag 是否稳定,比在办公室刷新一次浏览器有用得多。
中间层会改写什么
反向代理、CDN、WAF 都可能自行增删缓存头。常见情况是源站发了 ETag,边缘节点统一替换成自己的值;或者源站发了 Last-Modified,压缩处理后把它抹掉。还有一类是中间层把 304 缓存成 200 直接返回完整内容,表面上一切正常,实际每次抓取都在消耗带宽。
实用的核对顺序
- 用 curl 手动带上 If-None-Match 或 If-Modified-Since 请求目标 URL,确认返回的是 304 还是 200。
- 换多个出口 IP 重复同一步骤,观察 ETag、Last-Modified 是否一致。
- 在源站日志里区分 200 与 304 的数量,找出哪些目录的 304 占比异常偏低。
- 对确认每次都返回 200 的静态类 URL,检查是不是动态生成的头部让缓存标识失效。
- 如果 Sitemap 里列出的内容页确实每次都有正文改动,那返回 200 是合理的,不必强行改成 304。
不要为了 304 而 304
304 比例高不等于抓取健康。如果页面内容确实频繁更新,而服务器因为缓存标识长期不变一直返回 304,蜘蛛就看不到新内容。缓存头的作用是让没变的部分不必反复传输,而不是把所有请求都变成 304。核对的重点是返回的 304 是否与内容真实变化情况一致。
最后提醒,条件请求只是抓取链路中的一环。它能减少无效传输,但不会因此带来收录或排名上的直接收益,把它当成服务器资源和抓取节奏的调节手段更合适。