站点运营

站点运营:缓存头与 304,别让过期缓存拖住内容更新

很多站点只盯着 URL 结构和内链,却忽略了 HTTP 响应头里的缓存策略。本文梳理浏览器缓存、CDN 缓存与蜘蛛抓取缓存三者的区别,说明 Cache-Control 常用指令、ETag 与 Last-Modified 的作用,以及内容更新后仍返回 304 的常见原因,并给出一份可执行的检查清单。

站点运营

站点运营:缓存头与 304,别让过期缓存拖住内容更新

很多站点把注意力放在 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 头、协议与源站配置一致,否则容易出现同一页面存在两份缓存、不同节点内容不一致的现象。

一份可执行的检查清单

  1. 用 curl -I 查看主要页面类型的响应头,记录 Cache-Control、ETag、Last-Modified、Age。
  2. 连续请求两次,确认第二次是否为 304,以及 ETag 是否稳定。
  3. 修改一篇内容后立刻请求,确认缓存是否按预期失效。
  4. 检查 CDN 控制台的缓存规则,是否把 HTML 和静态资源混用同一套策略。
  5. 抽查多台后端,比较同一 URL 的 ETag 是否一致。
缓存策略的目标是让没变的少传、变了的及时到,而不是把页面钉死在某个版本上。

和更新节奏对齐

更新频繁的栏目可以给较短的缓存时间,长期不动的说明页可以放宽。把缓存时间和内容更新节奏对齐,比统一设一个全局值更省事,出问题时也更容易定位。改动上线后,记得同步观察日志里 200 与 304 的比例变化,这通常是最直接的反馈。