做蜘蛛池的人常常盯着“蜘蛛来了几次”这一个指标,却很少看“每次抓走多少字节”。入口页里大量内容是不变的链接聚合,如果每次抓取都把整页 HTML 重新传一遍,服务器带宽和响应时间都会被无谓消耗。缓存头里的 304 机制,就是用来压缩这部分开销的。
304 响应到底发生了什么
当蜘蛛第一次抓到入口页时,服务器会连同一组校验标识返回,常见的是 Last-Modified 和 ETag。下一次抓取时,蜘蛛会把这两个值放进 If-Modified-Since 和 If-None-Match 请求头。如果服务器判断内容没变,就回一个 304 Not Modified,响应体为空。
要注意两点:一是 304 依然算一次抓取请求,蜘蛛的访问计数、日志记录都不会少;二是它省下的是传输内容和部分处理时间,不是抓取次数。所以它解决的是“重复抓同一份内容成本高”的问题,不是“抓得太少”的问题。
哪些入口页适合开缓存
- 长期不动的链接聚合页、导航页、老榜单页;
- 侧栏、页脚一类公共区块的静态资源;
- 只承担“把蜘蛛引向目标页”职责、正文本身不更新的入口页。
反过来,需要频繁追加新链接的入口页、状态码经常变化的页面、做跳转分流的中间页,都不适合套长缓存,否则中间层可能一直返回旧内容,新加的链接反而更晚被发现。
头部信息怎么写更稳妥
- Last-Modified 用文件或内容的真实修改时间,别每次请求都写当前时间,那会让条件请求永远失效。
- ETag 避免用随进程变化的 inode、进程号、随机数拼接,否则同一份内容每次算出的值都不一样。
- Cache-Control 可以用 max-age 和 s-maxage 做分层,但不要图省事统一写 no-store,那等于把缓存这条路堵死。
- 两个校验值不要互相打架。同时给出 ETag 和 Last-Modified 是允许的,但逻辑要一致,否则会出现“这次 304、下次 200”的抖动。
几个常见的理解偏差
第一个偏差是把 304 当成“蜘蛛没抓”。日志里 304 会正常记一条,只是响应体为空,看访问记录时容易被当成无效请求过滤掉。排查抓取断点时如果只统计 200,就会漏掉这部分正常抓取。
第二个偏差是认为开了缓存就能提升抓取频率。缓存只影响传输体积和响应速度,蜘蛛是否再来、隔多久来,取决于它自己的调度和你页面释放的更新信号。把缓存当成“催蜘蛛”的手段,方向就错了。
第三个偏差是忽略中间层。CDN、反向代理、WAF 都可能重写 ETag 或补上 Age 头,你在源站配的值和蜘蛛实际收到的值未必一致。核对时用命令行工具直接看响应头,比凭配置页面猜要靠谱。
落地时的检查清单
- 先用命令行请求一次入口页,记录返回的 Last-Modified、ETag、Cache-Control;
- 用带条件请求的方式再抓一次,确认是否能正确返回 304;
- 抽查服务器日志,统计入口页里 2xx 和 304 的比例,看哪些页面长期重复传输;
- 内容更新时确认头部同步更新,避免出现“页面变了但校验值没变”;
- 按页面类型分层配置,聚合页可以放宽,新链接页保持较短缓存。
缓存是省资源的手段,不是提升抓取的手段。入口页能被发现、能被重访,仍然依赖链接结构、内容更新和正常的服务器响应。
把 304 和缓存头理顺,收益通常体现在带宽、响应时间和服务器负载上,而不是抓取条数的立刻上涨。把它当成入口页运维的一个基础动作,比指望它带来戏剧性变化要现实得多。