很多站点把注意力放在 URL 结构和内链上,却忽略了一个更底层的东西:HTTP 响应头里的缓存策略。它决定浏览器和中间节点看到的是新内容还是旧副本,也会影响搜索蜘蛛拿到的页面版本。缓存没配对,往往表现为“我明明改了,怎么还是老样子”。
三种容易混淆的缓存
- 浏览器缓存:由 Cache-Control、Expires 控制,主要影响回访用户。
- CDN 与反向代理缓存:节点上保留的副本,可能长期不更新。
- 搜索引擎自己的抓取缓存:蜘蛛按自身节奏重访,站点只能通过响应头和内容变化去引导。
这三者彼此独立。改了其中一个,另外两个不一定跟着变,所以排查时要分开看。
Cache-Control 怎么写更稳妥
对内容页,常见做法是给 max-age 一个中等值,配合 s-maxage 单独约束 CDN,必要时用 stale-while-revalidate 让节点先返回旧副本、后台再更新。这样既能减少回源压力,也不至于让页面长时间停在旧版本。
几个指令的差别
- no-store:完全不缓存,适合登录态页面,但会明显加大源站压力。
- no-cache:不是不缓存,而是每次都要回源校验,常和 304 配合出现。
- private:只允许浏览器缓存,CDN 不保存。
- immutable:适合带哈希的静态资源,不适合放在正文页。
正文页如果设成长期强缓存,编辑改完标题和内容后,在缓存到期前,用户和蜘蛛可能仍看到旧版本。
ETag 与 Last-Modified
这两个头是条件请求的凭据。客户端下次请求时会带上 If-None-Match 或 If-Modified-Since,源站判断内容没变就返回 304,既省流量也省时间。
需要注意的是 ETag 的生成方式。多台后端各自算出不同的 ETag,同一个 URL 在不同节点就会被判为“变了”,缓存命中率下降,日志里也会出现大量 200 而不是 304。Last-Modified 同理,如果它依赖某个没有随内容更新的字段,条件请求的结论就会失真。
304 不是错误
有些站长在日志里看到成片的 304 就紧张,其实这是正常的协商结果,代表缓存有效、内容未变。真正要盯的是另一种情况:内容明明更新了,回源依然返回 304。常见原因有两个,一是 Last-Modified 没跟着刷新,二是中间层把校验结果缓存住了。
CDN 与源站不一致
改版、迁移或批量修改标题之后,建议主动刷新 CDN 缓存,或者在发布流程里带上版本标识。同时确认回源的 Host 头、协议与源站配置一致,否则容易出现同一页面存在两份缓存、不同节点内容不一致的现象。
一份可执行的检查清单
- 用 curl -I 查看主要页面类型的响应头,记录 Cache-Control、ETag、Last-Modified、Age。
- 连续请求两次,确认第二次是否为 304,以及 ETag 是否稳定。
- 修改一篇内容后立刻请求,确认缓存是否按预期失效。
- 检查 CDN 控制台的缓存规则,是否把 HTML 和静态资源混用同一套策略。
- 抽查多台后端,比较同一 URL 的 ETag 是否一致。
缓存策略的目标是让没变的少传、变了的及时到,而不是把页面钉死在某个版本上。
和更新节奏对齐
更新频繁的栏目可以给较短的缓存时间,长期不动的说明页可以放宽。把缓存时间和内容更新节奏对齐,比统一设一个全局值更省事,出问题时也更容易定位。改动上线后,记得同步观察日志里 200 与 304 的比例变化,这通常是最直接的反馈。