很多站点在排查抓取异常时,会先看服务器日志、robots.txt 和站点地图,却很少想到另一层:蜘蛛拿到的 HTML,可能根本不是数据库里最新的那一版,而是缓存层吐出来的旧副本。缓存本身没有错,问题是缓存和抓取之间的关系没被管理好。
缓存把页面变成了两份
开了一整页缓存之后,同一个 URL 至少有两份内容:一份是源站刚生成的,一份是缓存节点上躺着的。用户访问时命中缓存,页面秒开;而搜索引擎蜘蛛来的时候,如果也命中同一份缓存,它看到的就是缓存生成那一刻的内容。内容更新后,蜘蛛可能过一阵才拿到新版本。
这件事本身不一定出问题。真正麻烦的是两种情况:缓存里存的是错误页面,或者不同访问者拿到的内容差异过大。
几类常见的不一致
1. 缓存了错误状态
源站某次抖动返回 500,或者数据库连接失败返回一个空壳页,如果这类响应被 CDN 按正常页面缓存下来,接下来一段时间所有访问者和蜘蛛都会拿到这个错页。常见表现是:日志里同一个地址反复返回 200,但内容却是空的。
2. 带登录态的差异
有些主题或插件会根据 Cookie 判断登录状态,未登录时展示摘要,登录后展示全文。如果缓存没有正确区分,蜘蛛(通常不带 Cookie)可能拿到一份权限受限的版本,正文大面积缺失。
3. TTL 设得太长
把 HTML 的缓存时间设成几天甚至几周,适合更新不频繁的静态页,但对栏目首页、文章页就不合适。新发布的内容如果只在源站可见,蜘蛛抓到的还是旧版,发现和收录都会被拖慢。
4. 地域与设备分流被缓存串味
多语言站点按 IP 判断语言、移动端返回精简版 HTML,这类分流如果和缓存策略没配合好,可能让蜘蛛在同一个地址上反复拿到不同语言的页面,导致它对这个地址的主版本判断摇摆。
自查清单
- 用一个干净的、不带 Cookie 的请求访问核心页面,检查返回内容是否完整,正文、标题、内链是否都在。
- 换一个常见的搜索引擎蜘蛛 UA 再请求一次,对比两次返回的 HTML 是否一致。
- 故意请求一个不存在的地址,确认返回的是 404,而不是一个被缓存的 200 空页面。
- 检查 CDN 后台有没有开启错误响应缓存,如果有,确认 5xx 的缓存时间是否被压到很短的秒级。
- 核对 Cache-Control 里的 s-maxage 与实际内容更新频率是否匹配,栏目页和文章页可以给不同档位。
- 看服务器日志里蜘蛛抓到的页面大小分布,如果同一批地址响应体忽大忽小,值得查一查缓存分层。
响应头可以怎么设
HTML 文档一般不建议让边缘节点长时间缓存。比较稳妥的做法是给一个较短的 s-maxage,配合 stale-while-revalidate,让节点在回源更新的同时继续提供旧内容,避免用户等待。真正需要长缓存的,是图片、CSS、JS 这类带版本号或指纹的静态资源,它们改名后地址会变,不容易出错。
同时留意 Vary 头。如果站点按 User-Agent 或 Accept-Language 返回不同内容,Vary 要写清楚,否则缓存可能把 A 的版本发给 B。写错 Vary 也会让缓存命中率下降,回源压力反而变大。
怎么确认蜘蛛看到的是什么
最直接的办法是拿日志说话。挑几个重点地址,记录蜘蛛访问的时间点、返回状态码和响应体大小,再和自己的手动请求做对比。如果响应体大小长期稳定,但页面内容其实已经更新过,基本可以判断命中的是旧缓存。也可以临时给这类地址加上较短缓存或直接绕过缓存,观察抓取到的内容是否随之变化。
另外,站点地图里的 lastmod 如果和缓存里实际的版本对不上,也容易让蜘蛛产生误判。更新内容之后,顺带确认一下缓存有没有被主动刷新,比等着 TTL 自然过期更省事。
缓存的目标是让用户更快看到内容,而不是让蜘蛛一直看到旧内容。把缓存时间、回源策略和内容更新节奏对齐,抓取和展示才会各自正常。