蜘蛛第一次抓取某个页面之后,再回来时通常不会从零开始。请求头里往往会带上 If-Modified-Since 或 If-None-Match,含义是「我上次拿到的是这个版本,如果内容没变,就别再发一遍正文」。服务器怎么回答,既决定这一趟抓取的开销,也影响蜘蛛把时间花在哪里。
蜘蛛重访时带的两个头
- If-Modified-Since:值来自上一次响应的 Last-Modified,服务器把页面当前的修改时间和它比一比。
- If-None-Match:值来自上一次响应的 ETag,相当于给内容算的一个版本标识,服务器比对标识是否一致。
两个头可能同时出现,服务器只要判断「没变」,就可以返回 304,不带正文。返回 304 并不是拒绝抓取,而是告诉蜘蛛:你手上那份还能用。
304 省下的是哪一段成本
对蜘蛛来说,抓到 304 意味着这一次不需要重新下载和解析整页内容,原有的正文、链接和索引信息可以继续沿用,只是把页面的「最近一次确认时间」往后推。对服务器来说,省下的是正文传输和带宽,而不是请求本身——请求还是来了。
当站内大量页面长期不变时,条件请求命中得越准,蜘蛛就越容易把有限的抓取额度挪到真正有新内容的路径上。反过来,如果每个页面都老老实实回 200 全量重传,抓取额度里就会多出一批重复劳动。这不会直接带来惩罚,但会让新 URL 和更新页排得更靠后。
几种把 304 用坏的做法
- 修改时间造假:每次请求都把 Last-Modified 设成当前时间,蜘蛛每次都得重新下载,条件请求形同虚设。
- 内容变了却回 304:页面明明已经改过,服务器仍按旧时间戳或旧 ETag 判断,蜘蛛会继续沿用过期内容,改动迟迟不生效。
- ETag 随机生成:每次请求算出来都不一样,蜘蛛每次都拿到 200,还多消耗一轮解析。
- 模板里的时间字段:页面底部嵌了「当前时间」之类的动态输出,导致整页指纹天天变,长效页面变成天天更新。
CDN 与多节点下的一致性问题
站点用了 CDN 或多台后端时,同一个 URL 从不同节点返回的 ETag 可能不一样。蜘蛛这次从 A 节点拿到一个标识,下次落到 B 节点,标识对不上,只能再取一遍全文。更麻烦的是边缘缓存与源站内容不同步:缓存里还是旧页面,源站已更新,回 304 的依据就成了旧版本。
处理思路不复杂:让 ETag 由内容本身决定,而不是由机器、进程或时间决定;源站更新时主动清一次缓存;必要时把 Last-Modified 也统一下来,别让不同节点各说各话。
用响应头自查
- 对同一 URL 连续请求两次,第二次带上 If-Modified-Since 或 If-None-Match,看状态码是不是 304。
- 换一台机器、换一个出口 IP 再试一次,确认不同节点返回的 ETag 是否一致。
- 改一次页面正文,再用旧标识请求,正常情况应返回 200 而不是 304。
- 在服务器日志里看 304 与 200 的比例,以及哪些路径几乎全是 200,那批页面往往就是条件请求没配好。
304 是省流量的手段,不是省抓取的手段。刻意堆 304 换来一个好看的比例,并不会让蜘蛛对站点更有兴趣;把 Last-Modified、ETag 和 Sitemap 里的 lastmod 对齐成同一套事实,才更容易让重抓节奏和实际更新对上。