Cache-Control 指令與 CDN 快取命中率:從 max-age 到 s-maxage 的完整指南
深入解析 Cache-Control 標頭(s-maxage、max-age、public 等)如何影響 CDN 快取命中率。
陳柏翰
網站效能工程師
本篇文章的核心是解析 Cache-Control HTTP 標頭——一個控制網頁資源如何被瀏覽器與 CDN 快取的關鍵機制。若你已具備快取基礎概念,本文將深入探討各指令(max-age、s-maxage、public、private 等)的實際行為與適用情境,並提供可直接套用的配置策略,幫助你顯著提升 CDN 快取命中率,進而改善網站載入速度與使用者體驗。從精準配置到如何驗證成效,這份指南將帶你完整掌握 HTTP 快取的進階應用。
快取不是只有瀏覽器:CDN 邊緣節點如何解讀 Cache-Control?
理解快取的第一步,是區分「瀏覽器快取」與「CDN 邊緣節點快取」這兩個不同層級。當你的伺服器回應一個請求時,Cache-Control HTTP 標頭會同時指導這兩層快取。然而,它們解讀指令的優先級與行為有所不同。瀏覽器主要關注 max-age 來決定本地快取的時間,而 CDN 作為一個分佈全球的共享代理快取,其核心指令是 s-maxage。這是一個關鍵的分別:s-maxage 的優先級高於 max-age,它專門為共享快取(如 CDN)設計,能覆蓋 max-age 的設定。這意味著,你可以對同一資源設定不同的快取策略,讓 CDN 快取更久,而瀏覽器快取較短。
另一個至關重要的指令是 public 或 private。預設情況下,HTTP 回應可能是可快取的,但若標記為 private,則表示回應內容僅限特定使用者(通常是瀏覽器)快取,CDN 或任何其他中間代理都必須跳過快取,每次請求都需回源。相反,public 指令明確允許包括 CDN 在內的任何快取儲存回應。因此,若要讓 CDN 有效快取你的資源,public, s-maxage=... 是一個常見且強大的組合。忽略這些差異,是導致 CDN 命中率低下的常見原因。
從零到九成命中率:實驗室配置與前後對比
提升 CDN 命中率的最直接方法,是針對不同資源類型實施精準的 Cache-Control 策略。一個行之有效的配置方案如下:對於靜態資源(如圖片、JavaScript、CSS 文件),設定 Cache-Control: public, max-age=31536000, immutable。這表示資源可被 CDN 和瀏覽器快取一年,且 immutable 告知瀏覽器在快取有效期內,無需發送任何條件請求(If-None-Match)來驗證,從而徹底避免不必要的請求。對於 HTML 文件(動態頁面),則設定 Cache-Control: public, max-age=60, s-maxage=300。這允許瀏覽器快取 60 秒以加快重複訪問速度,同時讓 CDN 快取 5 分鐘,在內容更新與快取效益間取得平衡。
如何測量你的 CDN 快取命中率?三個實用方法
第一個,也是最直觀的方法,就是檢查回應標頭。如前所述,在 Chrome 開發者工具的 Network 面板,或使用 curl -I 命令,查看 X-Cache、CF-Cache-Status、Age 等標頭。例如,Age: 120 表示該資源在 CDN 上已被快取了 120 秒。如果 X-Cache 值為 MISS,則表示 CDN 未命中,請求被轉發到了源站。這個方法適合進行即時、抽樣式的診斷。
第二個方法是解讀 Age 標頭的數值變化。當你重複請求同一資源時,如果 Age 的數值穩定增長且小於你設定的 max-age 或 s-maxage,說明它正在 CDN 邊緣節點的快取生命週期中。如果 Age 值突然重置或缺失,可能表示快取已過期或發生了回源。第三個方法則是查閱你的 CDN 供應商提供的後台儀表板或日誌分析。主流 CDN 如 Cloudflare、Fastly、Akamai 等,都會在控制面板中提供詳細的「Cache HIT Ratio」(快取命中率)報表,可以讓你看到全球或特定區域的整體命中率趨勢,這是進行長期優化和監控的最佳工具。
快取失效與更新:如何讓使用者總能看到最新內容?
長時間快取的挑戰在於,當內容更新時,如何確保使用者立即獲得新版。一個核心原則是:避免依賴 no-cache 作為主要的更新策略。no-cache 的真正含義並非「不快取」,而是「每次使用前必須向源站進行驗證」(即發送 If-None-Match 請求)。這雖然能確保內容新鮮,但仍然會產生網絡往返,增加延遲。真正的解決方案是結合長期快取與「快取破壞」(cache-busting)技巧,即在檔案網址中加入版本化資訊,例如將 style.css 改為 style.a3f8d2.css。當檔案內容改變時,其哈希值(hash)也會改變,生成一個全新的 URL。對於這個新 URL,所有快取(包括 CDN 和瀏覽器)都會視為一個全新的資源,從而自動獲取最新版本。這允許你安全地為靜態資源設定極長的 max-age。
實現自動化版本控制的最佳實踐,是在你的構建流程(build process)中,自動為輸出的靜態資源檔名附加內容哈希。現代的前端框架和打包工具(如 Webpack、Vite)都內建了此功能。服務端同樣可以在生成 HTML 或動態資源路徑時,動態插入最新的版本哈希。這種方法將內容更新與快取策略完全解耦:你可以對所有版本化的資源設定長期的 Cache-Control: public, max-age=31536000, immutable,在享受高效能快取的同時,確保內容更新能立即觸達所有使用者。
當快取失效時:must-revalidate 與 stale-while-revalidate 的妙用
在實踐中,有時你可能需要更精細地控制快取過期後的行為。must-revalidate 指令是一個強制性的約束,它要求客戶端(包括 CDN)在快取資源過期後,必須回到源站進行驗證,確認資源是否仍然有效,然後才能使用。這對於某些關鍵數據(如金融價格、庫存數量)至關重要,可以確保不會使用過期的數據。然而,濫用它可能導致「回源風暴」,即大量過期請求同時湧向源站,造成巨大壓力。
一個更溫和且能改善使用者體驗的指令是 stale-while-revalidate。你可以在 Cache-Control 中這樣設定:Cache-Control: public, max-age=60, stale-while-revalidate=3600。這表示資源在 60 秒內是新鮮的,可直接從快取提供。當快取過期後(60-3720 秒期間),CDN 可以立即向使用者返回這個「陳舊」的快取內容,同時在背景異步地向源站發起驗證請求以獲取新版本。下次請求時,如果背景驗證已完成,就會返回新內容;如果未完成,則再次返回陳舊內容並觸發新的背景驗證。這種策略顯著降低了使用者感知的延遲,因為他們不需要等待回源完成就能繼續操作,而內容也會在短時間內靜默更新。
s-maxage 和 max-age 有什麼不同?在什麼情況下我應該使用 s-maxage?
max-age 指令告訴瀏覽器(以及任何快取)資源可以快取多久。s-maxage 則是一個專為「共享快取」(如 CDN 邊緣節點)設計的指令,它的優先級高於 max-age。當回應同時包含兩者時,CDN 會遵循 s-maxage,而瀏覽器會繼續使用 max-age。當你需要為 CDN 設定一個比瀏覽器更長或不同的快取時間時(例如,讓 CDN 快取 HTML 5 分鐘,但瀏覽器只快取 1 分鐘),就應該使用 s-maxage。
如何確認我的資源是否被 CDN 快取了?
最直接的方法是檢查 HTTP 回應標頭。你可以使用瀏覽器的開發者工具(在 Network 面板點擊資源,查看 Headers),或使用命令行工具 curl -I [資源網址]。尋找 X-Cache、CF-Cache-Status 或類似的標頭,其值為 HIT 即表示命中 CDN 快取。Age 標頭的數值則表示資源在 CDN 上已被快取了多少秒。
為什麼不推薦將 Cache-Control 設為 no-cache 來確保內容新鮮?
因為 no-cache 的真實含義是「每次使用前必須向源站驗證」,而非「不進行快取」。它仍然允許快取,但每次請求都會強制發送一個條件驗證請求到源站,這會增加網絡延遲和源站負擔。更好的做法是使用「快取破壞」(cache-busting)策略,例如在資源檔名中加入版本哈希(如 style.a3f8d2.css),並為這些帶哈希的資源設定極長的 max-age 和 immutable。這樣既享受了長期快取的性能紅利,又能在內容更新時自動失效。
stale-while-revalidate 是如何改善使用者體驗的?
stale-while-revalidate 指令允許 CDN 在資源快取過期後,仍然立即返回這個「陳舊」的快取版本給使用者,同時在背景靜默地向源站發起驗證以獲取新版本。這避免了使用者因等待回源響應而感受到的延遲或白屏。對於大多數內容型網站,這種幾秒鐘的舊數據通常是可以接受的,而使用者感知到的載入速度卻得到了顯著提升。
如何為我的靜態資源自動生成帶有版本哈希的檔名?
這通常通過前端構建工具自動化完成。例如,在使用 Webpack 時,可以在配置中使用 [contenthash] 占位符作為輸出檔案名(如 bundle.[contenthash].js)。每次構建,若文件內容改變,哈希值就會變化,從而生成新檔名。Vite 等現代工具也提供了類似功能。在服務端,你可以使用 Gulp 等任務運行器,或在部署腳本中調用工具來自動完成這個過程。