站点运营

站点运营:CDN 缓存與刷新自查,別让更新後的頁面還在發舊版本

内容更新後頁面還是舊版本,多半是缓存层没跟上。本文梳理浏览器缓存、CDN 邊缘缓存與服務端缓存的区別,說明如何通過响應头判断命中情况,如何為 HTML 與静態资源設定不同策略,以及更新後的刷新與驗證流程,帮助站点运营把缓存纳入日常巡检清單。

站点运营

站点运营:CDN 缓存與刷新自查,別让更新後的頁面還在發舊版本

把一篇文章改好了标题、补好了内鏈,發布之後自己看着没問题,但同事打開還是老样子,搜尋引擎抓到的也可能是几天前的版本。這種“發布成功、頁面没變”的情况,多數不是發布失敗,而是缓存层還在拿舊副本。做站点运营的人,需要知道自己的站点到底有几层缓存,以及每一层什么时候會更新。

先搞清楚有哪几层缓存

一個訪客看到的頁面,通常會经過這几道關口:

  • 浏览器缓存:訪客本地儲存的副本,由响應头决定它多久不回来問服務器。
  • CDN 邊缘节点缓存:离訪客最近的机房儲存的副本,命中时不回源。
  • 服務端缓存:頁面缓存插件、反向代理、對象缓存等,在源站内部再存一层。
  • 資料库查询缓存:某些 CMS 會把查询结果暂存,内容更新後需要主動清理。

排查时按“离訪客最近的一层”往回走,比盲目点一遍“清除缓存”更有效。

用响應头判断命中了哪一层

同样的地址连續請求两次,對比返回头就能看出不少信息。重点看這几項:

  • Cache-Control:max-age 有多長,是否带 s-maxage、stale-while-revalidate。
  • Age:副本已经在邊缘放了多久,數字很大說明命中缓存。
  • X-Cache、CF-Cache-Status 之類的头:HIT、MISS、EXPIRED、DYNAMIC 直接告诉你结果。
  • Last-Modified、ETag:用于协商缓存,内容變了這两個值應该跟着變。
  • Vary:如果带了 Cookie 或 User-Agent,缓存會按维度分片,命中率明顯下降。

如果更新内容之後 Age 一直不清零,說明邊缘缓存没有被刷新;如果 Age 很小但内容還是舊的,問题更可能在源站那一层。

HTML 和静態资源應该用不同策略

一刀切的缓存設定往往两头不讨好:设短了,静態资源反复回源;设長了,文章改完迟迟不更新。比較常见的做法是分開處理。

  • HTML 頁面:設定較短的 max-age,或者走协商缓存,让浏览器每次都回来確認一次。
  • 带指纹的 CSS、JS:文件名里带哈希或版本号,可以放心用一年以上的長缓存和 immutable。
  • 图片、字体:同样适合長缓存,但替換素材时要換文件名或加參數,不要直接覆盖原文件。
  • 带登入態或個性化的頁面:不要做公共缓存,或者明确声明 private。

另外,栏目頁、标簽頁、搜尋頁這些容易被频繁訪問又變化較快的地址,要單獨看一眼它們的缓存策略,別和文章頁混在一起配置。

缓存键和 URL 參數容易被忽略

带追踪參數的分享連結、排序篩選參數,如果全部当作獨立的缓存键,會在邊缘留下大量内容几乎相同、只差几個字符的副本。這既占用存储,也让刷新變得麻烦。可以配置忽略不影响内容的參數,只保留真正决定頁面内容的字段。同时確認站点没有把同一篇内容暴露成多個可缓存的地址,否則刷新时容易漏掉其中一部分。

更新内容後的刷新與驗證流程

把刷新動作固定成流程,比每次凭感觉操作更稳:

  1. 先在源站直接確認内容已经改好,回源請求拿到的是新版本。
  2. 按具体 URL 精确刷新,而不是一上来就全量刷新。
  3. 如果改的是模板或公共区块,考虑目錄級刷新。
  4. 刷新完成後预热几個主要入口頁,避免第一批訪客回源压力過大。
  5. 用無痕窗口或另一台设备再打開一次,排除本地浏览器缓存的干扰。

顺带检查几個容易漏的地址:XML sitemap、RSS 或 feed、栏目的第一頁,以及之前被分享出去的老連結。這些地方往往挂在同一個域名下,却用了不同的缓存規則。

纳入日常巡检的几項

  • 發布重要更新後,確認目标頁面的 Age 與内容版本一致。
  • 抽查首頁、栏目頁、文章頁三類模板的响應头,確認設定没有被改回預設。
  • 確認静態资源更新後文件名或版本号确實變了。
  • 關注缓存命中率的變化,突然下降通常意味着參數或規則出了問题。
  • 记錄每次全量刷新的時間和原因,便于事後對比流量與回源日誌。

缓存本身是為了让站点更快,不是為了让人猜不透。把“改完内容、刷新、驗證”這三步寫進發布清單,多數“頁面更新了但別人看到還是舊的”的問题,都能在几分钟内定位到是哪一层没跟上。