条件请求在抓取流程中的位置
搜索蜘蛛访问一个已抓过的 URL 时,通常会带上 If-Modified-Since 或 If-None-Match 请求头。服务器如果判断内容没有变化,返回 304 Not Modified,蜘蛛就不再下载正文,只更新一下抓取记录。这个机制的作用很直接:减少传输量,把有限的抓取预算留给新页面和确有更新的页面。
问题在于,304 的命中依赖两个响应头:Last-Modified 和 ETag。只要其中一个被错误地生成、被中间层改写,或者条件请求头根本没传到源站,蜘蛛就会一直在“全量下载”和“偶尔命中”之间反复,抓取效率明显下降。
常见异常类型
ETag 每次都变
有些框架默认用 inode、进程 ID、时间戳拼接 ETag,同一份内容在两次请求里会拿到两个不同的值。蜘蛛下次带着旧 ETag 来对不上,只能重新拉全文。这类问题在动态渲染、多实例部署、负载均衡后的站点上特别常见。
Last-Modified 失真
- 每次请求都刷新为当前时间,等于告诉蜘蛛“内容刚刚变了”。
- 时间字段早于实际修改时间,导致蜘蛛认为页面长期未更新。
- 时间戳使用未来时间,部分客户端会直接忽略该头。
- 内容更新后没有同步修改时间,304 继续命中,蜘蛛看不到新内容。
CDN 与源站的头不一致
边缘节点开启压缩、内容改写或图片处理时,可能重新生成 ETag。结果是源站 ETag 与边缘 ETag 对不上,蜘蛛从不同线路访问得到不同校验值,304 命中率被拉低。回源请求头被剥离的情况也存在,源站实际上一直返回 200,条件请求等于没有生效。
304 与 200 交替出现
部分站点在同一 URL 上时而返回 304、时而返回 200 并附带正文,且两次内容并不一致。这通常和缓存策略、灰度发布、多机房数据不同步有关。对蜘蛛来说,这会增加判断成本,也容易造成重复抓取。
排查顺序
- 先看抓取日志中 304 的占比。如果长期接近零,说明条件请求基本没有生效。
- 用同一 URL 连续请求两次,记录两次的 ETag 与 Last-Modified 是否稳定。注意要分别从源站地址和对外域名各测一次。
- 手动带上旧的 If-None-Match、If-Modified-Since 发起请求,观察是返回 304,还是被忽略后直接返回 200。
- 检查 CDN 回源配置:是否改写响应头、是否剥离条件请求头、是否对 HTML 做了额外处理。
- 检查应用层缓存开关。不少 CMS 或框架对登录态、动态参数页面默认关闭缓存,这类页面自然拿不到 304。
- 核对内容更新流程:编辑发布之后,Last-Modified 是否随内容真正发生变化。
配置建议
- ETag 建议基于内容哈希生成,同一内容稳定输出同一个值。
- Last-Modified 与内容实际变动时间保持一致,不要伪造时间。
- HTML 与静态资源分开配置缓存策略,不要共用一套规则。
- CDN 回源时保留条件请求头,边缘 ETag 与源站 ETag 不要随意重写。
- 多机房、多实例站点确认内容版本同步,减少 304 与 200 交替。
304 命中率高不代表内容会被更新收录,它只说明这一次没有重复传输。内容是否进入索引,仍取决于页面本身的质量和抓取后的处理。
条件请求是抓取效率里比较容易被忽略的一环。把它和抓取日志、CDN 回源配置放在一起核对,通常能发现一部分“蜘蛛反复来、页面却没变化”的抓取浪费。