内容发布完就顺手点一下提交入口,是很多人的固定动作。但提交之后蜘蛛真正抓到的,未必是你刚写好的那一版。中间隔着的 CDN、反向代理、页面缓存,只要有一层还留着旧副本,蜘蛛拿到的就是旧内容,而且它并不知道这是旧的。
缓存可能存在于哪几层
排查之前先有个大致的地图,不然容易只刷新一层就以为搞定了。
- 浏览器缓存:主要影响回访用户,对蜘蛛的影响相对小,但会影响你自己判断页面是否真的更新了。
- CDN 边缘节点:最容易出问题的一层。不同节点的缓存时间不完全一致,同一 URL 在一处是新版、另一处是旧版,并不罕见。
- 反向代理与页面缓存:Nginx 的 fastcgi_cache、Varnish、各类整页缓存插件都属于这一层。
- 应用层对象缓存:缓存的是数据库查询结果或页面片段,外壳是新的,正文却还是旧的。
缓存没刷新时,蜘蛛实际会看到什么
这些现象往往不会立刻暴露,容易和别的问题混在一起。
- 标题和描述仍是修改前的版本,搜索结果里长期显示旧标题。
- 列表页和首页没有出现刚发布的文章,蜘蛛顺着列表走也找不到新入口。
- 已经下线或删除的页面仍然返回 200 和完整内容,相当于旧页面一直还在。
- 比较麻烦的一种:新页面正式上线前被访问过,404 被缓存下来,蜘蛛来的时候拿到的还是 404。
几个值得关注的响应头
用命令行工具或浏览器开发者工具看一眼响应头,通常比反复猜测快得多。
- Cache-Control:重点看 max-age 和 s-maxage。s-maxage 针对的是共享缓存,也就是 CDN 那一层,很多人只调了 max-age 却漏掉了它。
- stale-while-revalidate:允许先返回旧内容、再去后台更新。对用户是友好的,但蜘蛛拿到的可能正是那份旧内容。
- Age:表示这份副本在缓存里已经放了多久。Age 很大而内容没变,说明缓存命中;Age 很小却仍返回旧内容,反而说明刷新没生效。
- Vary:设置不当时,移动端和桌面端可能互相拿到对方缓存的版本。
内容更新后可以固定下来的动作
- 确认这次改动影响的 URL 范围:只有详情页,还是栏目页、首页、站点地图都要一起动。
- 按层刷新:先应用层缓存,再 CDN,必要时刷新目录而不只是单个 URL。
- 用绕过缓存的请求验证一次,确认返回的确实是新内容。
- 如果站点地图或订阅源有更新,顺手也刷新一遍,它们本身就是蜘蛛的发现入口。
- 把这一步写进发布流程,而不是依赖某个人正好记得。
和搜索蜘蛛之间的关系
需要说清楚的是,蜘蛛拿到旧版本并不等于出错。抓取本来就是异步的,它这次看到旧内容,下次再来还能看到新的。真正的影响是时间差:新内容被发现得晚,旧内容在索引里留得久,删掉的页面可能继续被访问到。
另一个常见误区是“为了保险,全站设成 no-store”。这样做确实不会缓存到旧内容,但每次访问都要回源,服务器压力上来之后,蜘蛛的抓取速度反而可能下降。更稳妥的做法是区分对待:列表页、首页这类更新频繁的页面缓存时间短一些,详情页可以长一些,但前提是刷新通道是通的。
缓存本身不是问题,失控的缓存才是。你要的不是“永远不缓存”,而是“更新之后能立刻换掉”。
一份可以定期过一遍的清单
- 随机抽几个最近更新过的页面,看响应头里的 Age 和实际内容版本是否一致。
- 确认 404、410 这类状态码没有被长时间缓存。
- 确认 301 跳转的缓存时间没有设得过长,改版调整时才好转弯。
- 确认发布、修改、删除三种操作都有对应的刷新动作。
- 记录一次刷新到生效大致需要多久,心里有个数。
这些事情单独看都不复杂,麻烦的是分散在不同人的手里。把它写进发布清单,比事后反复追问“为什么蜘蛛还没看到新页面”要省事得多。