很多蜘蛛池入口页的疑难问题,最后会落到缓存上。你本地打开看到的是新版本,蜘蛛抓到的可能是几小时前甚至几天前的旧版本。这不是蜘蛛记性差,而是请求在到达源站之前,就被某一层缓存截住了。
一、请求到源站前会经过哪几层缓存
一次蜘蛛抓取,通常要穿过下面几层,任何一层给出缓存副本,源站就不会被访问。
- 浏览器缓存:只影响真实用户,蜘蛛一般不复用本地缓存,排查时可以忽略。
- CDN 边缘节点:影响最大的一层。不同节点的缓存状态可能不一样,同一 URL 在不同地区抓到的版本未必相同。
- 反向代理与网关:Nginx、Varnish 之类的缓存层,规则不清时容易长期返回旧内容。
- 对象存储与静态托管:如果入口页是静态文件,还要看它的缓存策略和刷新机制。
二、和蜘蛛拿到的版本相关的几个响应头
蜘蛛不执行复杂的缓存逻辑,但它拿到的是哪一份副本,基本由下面这些头决定。
- Cache-Control:max-age 决定副本能存活多久。给入口页设过长的 max-age,更新后蜘蛛还会拿到旧版。
- ETag / Last-Modified:源站用它们判断内容有没有变。如果这两个值在更新后没变,缓存层会认为内容没动。
- Vary:声明按哪些请求头区分缓存。比如按 User-Agent 分版本,一旦写错,蜘蛛可能拿到给移动端的那份。
- Age / X-Cache:排查时最直观的两个头,Age 显示副本存活了多久,X-Cache 会告诉你这次是命中还是回源。
三、几个容易被缓存坑到的场景
1. 更新内容后蜘蛛仍抓旧版
最常见的情况。改完入口页只刷新了自己的浏览器,CDN 节点并没有刷新。建议更新后主动做一次缓存刷新,等回源生效后再观察日志。
2. 带参数的 URL 被当成独立副本
入口页 URL 上带 utm、from、ref 之类参数时,有些 CDN 会把它们当成不同资源分别缓存。结果同一篇内容在缓存里存了好几份,更新时只刷了一份。
3. 回源失败返回旧内容
部分缓存配置在源站超时或 5xx 时会返回过期副本。蜘蛛看到 200 和正常内容,但源站其实已经挂了。这种情况日志里不容易发现,需要看回源监控。
4. 按 UA 分版本导致串味
为不同蜘蛛准备不同版本时,如果 Vary 没写对,CDN 会把 A 蜘蛛的副本发给 B 蜘蛛。入口页内容本身没坏,但分发错了。
四、实操建议
- 入口页的缓存时间不要设太长,尤其是内容还在调整的阶段,几十分钟到几小时比几天更稳妥。
- 每次更新后主动刷新缓存,并在刷新后用一个不常见的 UA 请求一次,确认返回的是新版。
- 用 curl -I 检查响应头,重点看 Cache-Control、Age、X-Cache、ETag。这一步比翻日志快。
- 如果入口页是静态文件,尽量让文件名或路径带版本标识,避免和旧缓存冲突。
- 给不同蜘蛛分版本时,先确认缓存层是否支持按 UA 区分,再看 Vary 写得对不对。
- 记录一次完整的抓取链路:蜘蛛请求到的节点、返回的 Age、是否回源。出问题时比盲猜有效。
缓存不改变内容本身,只改变蜘蛛什么时候看到哪一版。把这一层理清楚,很多关于蜘蛛不抓新内容的疑问会有答案。
缓存层的价值是减少源站压力,对蜘蛛池入口页来说,它同时是一层看不见的变量。不必把它当成敌人,但要知道它什么时候会挡住你想让蜘蛛看到的东西。定期检查响应头,比事后从日志里倒推省力得多。