很多站点把注意力放在 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 的比例變化,這通常是最直接的反馈。