搭蜘蛛池的时候,大家往往盯着页面内容、链接结构、域名历史,却很少回头看 HTTP 响应头。实际上蜘蛛每次抓取拿到的第一手信息就是响应头,缓存策略配得不对,蜘蛛可能白跑一趟,也可能反复拉取同一份内容。
缓存头为什么会影响蜘蛛
普通用户的浏览器缓存是为了省流量、加快二次访问;抓取器同样会遵循一部分 HTTP 缓存语义,尤其是条件请求相关的那几个字段。区别在于,蜘蛛更在意「内容有没有变」,而不是「加载快不快」。如果服务器长期只回 304,蜘蛛会认为页面没更新,来的频率自然下降;如果每次都回 200 且内容完全一样,抓取成本偏高,也浪费了抓取预算。
几个关键响应头怎么理解
Cache-Control
常见的 max-age 表示资源在多少秒内被视为新鲜。对入口页这类需要经常被发现的页面,设置过长的 max-age(比如一天以上)意义不大,因为蜘蛛的抓取间隔往往由自身策略决定,不完全受它约束。更稳妥的做法是给一个中等长度的缓存时间,让 CDN 能缓存,同时源站的更新仍能及时反映出来。
no-cache 和 no-store 经常被混用。no-cache 表示可以缓存但每次要回源校验,no-store 表示完全不缓存。入口页一般不需要 no-store。
ETag 与 Last-Modified
这两个字段用来支持条件请求。蜘蛛带上 If-None-Match 或 If-Modified-Since 再来时,服务器判断内容没变就回 304。问题常出在两类情况:一是动态生成的 ETag 每次都不一样,比如带上时间戳或进程 ID,导致永远回 200,缓存形同虚设;二是内容明明更新了,Last-Modified 却没跟着变,蜘蛛拿到的还是旧判断。
Vary
如果入口页会根据 User-Agent 返回不同内容,一定要在 Vary 里声明,否则中间缓存可能把 A 版本发给 B 请求。更需要注意的是,有些站群程序给蜘蛛版和用户版返回差异过大的页面,这在搜索质量评估里属于高风险行为。
X-Robots-Tag
这是写在响应头里的 robots 指令,作用与 meta robots 类似。排查「页面明明能访问却迟迟没有动静」时,别忘了检查这个头里有没有被加上 noindex。它经常出现在 CDN 或安全策略的默认配置里,最容易被忽略。
304 太多或太少都不是好事
长期只回 304,说明页面确实没变,但入口页如果几个月都不更新,蜘蛛的访问动力会下降。反过来,每次请求都回 200 且内容一模一样,也会让蜘蛛觉得这个页面不值得反复来。比较合理的节奏是:入口页有实质更新时,内容变了、ETag 跟着变、正常回 200;没有更新的周期里,让 304 正常工作。
几个容易踩的坑
- 用脚本生成随机 ETag,看着像在优化缓存,其实是把缓存彻底废掉。
- CDN 缓存时间远长于源站更新频率,导致蜘蛛抓到的是过期版本。
- 把所有入口页设成 no-store,等于要求沿途每个节点都回源,源站压力集中。
- 服务器时间不准,Last-Modified 出现未来时间,条件请求的判断会乱。
- 响应头里同时出现多条 Cache-Control,语义冲突时行为难以判定,最好只保留一条。
一个可落地的配置思路
- 先确认入口页的更新频率,据此定缓存时间,不要照搬静态资源的配置。
- ETag 用内容哈希生成,而不是随机值或时间戳。
- 保证 Last-Modified 与内容实际变更时间一致,服务器时钟保持同步。
- 如果做了 UA 分流,Vary 要写清楚,并尽量让不同版本的核心内容一致。
- 上线后抽查响应头,用 curl -I 看一遍,通常比在浏览器里看更准。
- 改完观察一段时间的抓取日志,看 304 与 200 的比例是否接近预期。
缓存和响应头是抓取链路上的基础设施,调好它们不会直接带来效果,但配错了一定会拖后腿。
整体来说,这类配置没有标准答案,取决于入口页的更新节奏和资源结构。与其把它当成一次性的技术细节,不如当成日常巡检的一部分,配合日志复盘,问题通常能在早期被发现。