Sanyanggae LogoSanyanggae

💻 Web前端開發

HTTP 快取的 no-cache 與 no-store 差在哪裡?用 ETag、304 確認更新

區分儲存與重新驗證,透過虛構開放時間表解讀 Cache-Control、ETag、304 回應,逐步找出舊畫面的原因。

사냥개 (Sanyanggae)發布 更新 6 分鐘閱讀

本文譯自韓文原文。 韓文原文 · 翻譯檢核: AI檢核

HTTP 快取說明圖:儲存與重複使用、ETag 重新驗證、200 與 304 回應
Sanyanggae 製作的說明圖:儲存與重複使用、ETag 重新驗證、200 與 304 回應。

假設圖書館網站改了今天的開放時間,部分訪客卻還是看到舊時間。首先要分清楚:伺服器的原始內容是否尚未改動、瀏覽器是否再次使用已儲存的回應,或是中間伺服器提供了先前版本。重新整理畫面好幾次,並不能單憑這件事判定問題出在哪一個環節。

HTTP 快取會儲存收到的回應,並在條件符合時再次使用。本文以公開開放時間表為虛構案例,串連 Cache-Control 的儲存、重新驗證指令與 ETag、304 回應。下方通訊紀錄是為了理解而縮減的範例,並非測量真實圖書館或特定伺服器所得。目標是說明哪些回應應能在何時重新使用,而非直接要求把所有快取清掉。

1. 分別考慮要不要存、要不要驗證,以及能與誰共享

閱讀快取政策時,分別寫下三個問題:是否可以儲存回應、下次請求能否直接使用儲存版本,以及能否讓多位使用者共享。允許儲存不表示隨時都能再用;確認內容是否最新,也不表示可以與其他人共享。HTTP 快取標準 RFC 9111以不同指令定義這些條件。以下以未另外附上欄位名稱引數的回應指令為說明範圍。

要判斷的問題相關回應指令應區分的意義
回應是否不應儲存no-store禁止為後續重新使用而儲存
再次使用前是否要確認no-cache可以儲存,但再次使用前必須成功驗證
能否由多位使用者共享private排除共享快取的儲存,但不禁止私人快取儲存

例如,公開時間表若經常在同一個網址更新,可以考慮要求即使有儲存版本,也應先確認再用。個人頁面與公開時間表,首先就有不同的共享條件。private 是對共享快取的指令,無法取代登入與權限檢查。若把目的不同的設定混成一句話,可能在改善速度時弄錯資訊可以提供給誰。

政策表除了指令,也要記下原因。例如,時間表是否為需要確認更新的公開資訊、標誌圖片是否為內容固定的檔案,以及同一網址是否呈現個人資訊。這張表是分類實際回應的起點,並不是適用於所有網站的完整設定。也要區分它針對的是瀏覽器、CDN 等哪一種儲存位置。

2. 選擇 no-cache 與 no-store 時別只看名稱

no-cache 的名稱容易讓人以為是禁止儲存,但回應中的 no-cache 是指再次使用儲存版本前必須驗證。伺服器確認內容沒有改變時,就有機會繼續使用儲存的本文。相對地,no-store 是不要儲存這次回應的指令。要不要保留與下一次要確認什麼是兩件事,不能預期兩種設定具有相同的行為。

快取中的 fresh 表示按照政策可以不經額外驗證就再次使用,並不保證管理者在這段時間沒有修改內容。若以 max-age 設定可再次使用的期限,即使原始內容在期限內更新,儲存的回應仍可能被採用。應先決定能接受多長的更新延遲,再把需求與指令連結。不要把任意的長期儲存時間當作效能改善的標準答案照抄。

MDN 的 HTTP 快取指南說明,在新回應加上 no-store,不會刪掉同一 URL 先前已儲存的回應。如果舊版本仍然有效,還沒有去抓取新回應,新標頭也可能尚未送達。因此別把 no-store 當成清除全部快取或保護隱私的充分條件;也應檢查舊回應的有效期間,以及可管理快取的更新程序。

3. 用 ETag 與 304 追蹤一次再次造訪

假設虛構時間表網址 /hours.json 最初顯示 18 時閉館。以下以說明用的 HTTP/1.1 格式只保留必要部分,真實回應所需的其他標頭已省略。hours-v1 是範例中伺服器選定的表示識別碼,不是計算時間的公式,也不表示真實檔案的雜湊值。

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache
ETag: "hours-v1"

{"closes":"18:00"}

如果瀏覽器已儲存這份回應,下次就可以透過條件式請求的 If-None-Match 傳送 ETag 值。伺服器認定與目前選定表示的條件相符、內容沒有改變時,會回傳 304 Not Modified。下方是將請求與對應回應連續列出的精簡紀錄,並不是在 304 後重新附上一份時間表 JSON。

GET /hours.json HTTP/1.1
Host: library.example
If-None-Match: "hours-v1"

HTTP/1.1 304 Not Modified
Cache-Control: no-cache
ETag: "hours-v1"

如同 MDN 的 ETag 說明,這種情況下用戶端會使用儲存的本文。304 沒有新本文,但仍有請求與驗證所需的通訊。如果管理者把閉館時間改為 19 時,伺服器的表示也已改變,面對舊條件便可預期回傳含新本文、新識別碼的 200 回應。使用 no-cache 不表示每次都會得到 304,也不表示資料庫查詢就會消失。

應確認的是內容與識別碼是否對應,而不只是狀態碼。內容變了卻沿用舊 ETag,可能產生錯誤的驗證結果;反之,內容相同但識別碼不斷改變,則可能增加重傳本文的次數。必須在伺服器端確認產生方式與所選表示的關係,不能光看到 ETag 就認定實作正確。

4. 區分經常變動的文件與採用新名稱的資源

像時間表這類在相同 URL 更新內容的文件,與內容變動就給予新檔名的標誌、指令碼,可能需要不同的更新策略。例如,若設計上將 logo.a1.png 換成 logo.b2.png,就要讓新文件指向新網址。若在檔名放了識別碼,卻仍覆寫舊檔案的內容,就破壞了同時管理網址與內容的約定。

上傳新檔案本身,不會讓訪客自動請求新網址。訪客取得的 HTML 若仍指向舊標誌網址,仍可能再次使用舊資源。因此除了資源的快取設定,也要檢查引用它的文件如何更新。與其把文件和資源都設為相同儲存時間,更應分別說明它們可以多晚才更新。

部署時,新舊文件可能暫時同時存在。在新資源準備好之前公開新文件,或過早刪除舊資源,都可能造成其他故障。這個虛構案例可以同時確認新文件引用的檔案是否存在,以及舊文件引用的檔案是否仍能存取。變更檔名是快取設計的工具,並不能自動解決所有部署順序與回復舊版的問題。

5. 在 Network 面板逐一驗證假設

親自確認時,先在允許快取的狀態留下基準紀錄。同時查看正確的 URL 與查詢參數、畫面顯示的時間表版本、回應狀態、請求的 If-None-Match,以及回應的 Cache-Control、ETag。即使名稱相同,請求標頭與回應標頭也是不同主體提出的條件,要記清楚讀的是哪一方。Chrome DevTools Network 文件說明了如何在 Headers 分開查看這些項目。

虛構測試情境一起查看的紀錄不宜貿然做出的結論
再次請求同一時間表條件式請求、狀態、畫面時間因為是 304,所以完全沒有通訊
修改原始時間後請求新本文、ETag、實際請求 URL出現儲存成功訊息,就已反映到所有使用者
關閉瀏覽器快取後請求首次下載與一般再次造訪的差異這等同於平常再次造訪的速度
按上一頁返回有沒有新請求及復原的畫面畫面出現,就一定有新的 HTTP 驗證

接著把停用瀏覽器快取當成獨立的測試條件。Chrome 的 Disable cache 設定在 DevTools 開啟期間生效,因此要一起記錄工具保持開啟的狀態與設定值。它有助於觀察首次下載,卻不同於檢查一般再次造訪如何使用儲存版本。若沒記錄是否啟用設定,可能從每次重新下載的結果誤判快取沒有運作。留下實驗條件,才能回到允許快取的狀態比較。

觀察時不要一次進行多項修改和請求,會比較容易縮小原因範圍。先保持內容不變確認再次造訪,再改一個時間欄位,觀察回應如何變化。如果同時修改文件 URL、伺服器設定與檔名,就難以判斷是哪一項造成結果。沒有出現預期的 200 或 304 時,應先重讀實際請求與回應,再考慮增加設定。

6. 一起確認其他儲存路徑與完成標準

停用瀏覽器的 HTTP 快取,不表示伺服器前方的 CDN 或應用程式其他儲存路徑也消失了。可以分別確認服務工作執行緒是否處理請求、中間伺服器如何挑選回應,以及應用程式是否把已取得的資料繼續留在畫面上。不能因為 URL 相同,就假設每一層都在使用同一份副本。

返回上一頁也要與新的 HTTP 請求分開確認。瀏覽器復原先前工作階段的畫面時,即使帶有 no-cache,也可能看不到預期的重新驗證請求。若立刻將它視為伺服器忽略標頭的證據,就可能找錯原因。分別記錄新導覽、重新整理與返回上一頁時是否實際發出請求,可避免把不同現象混為一談。

時間表範例的完成標準,不只有快取命中率。還應確認內容未改變時能否正確使用儲存版本、變更後是否在允許時間內顯示新資訊,以及共享回應的對象是否正確。留下變更與觀察時刻、條件及實際本文,能讓其他人較容易重現相同情境。速度數據雖改善,錯誤開放時間卻持續顯示很久,仍不符合原先需求。

正式使用時,應依回應類型一起檢查策略、更新與回復程序。不要將公開文件的快取指令複製到個人回應,也不要將驗證成功當作權限檢查已完成。標頭傳達的是儲存與再次使用的規則。能說清楚儲存了什麼、經過哪些確認才形成目前畫面,才能更準確診斷舊畫面問題。

依據與參考資料

本文依據公開資料進行說明。標示出處不代表相關機構曾審閱或認證本文。

關於經營者與聯絡方式

同主題的其他文章