Skip to content
所有文章 ‹ Part 04 of 18 · Cache 不是方塊,是一條鏈
工程 · 3 min read

Cache 的新鮮度:fresh、stale 和 304

HTTP cache 怎麼用 max-age 和 Age 判斷副本是 fresh 還是 stale、304 refresh 怎麼運作,以及為什麼前面的 cache 只會跟收到的副本一樣新。

Cache 存一份副本,下一個 request 就不用跑到 server。用後端的話說,它是放在慢函式前面的 memo cache。

Memo cache 最難的地方,是決定什麼時候該丟掉舊值。HTTP cache 用 max-age 和 Age 兩個數字來決定。

browser CDN cache (只在需要時) origin hit: 這裡有新鮮的副本,幾毫秒內回應 miss: 沒有副本,或副本太舊,去問 origin
hit 在 CDN cache 幾毫秒就回應,只有 miss 才會走到 origin。

max-age 和 Age

max-age = 3600 s fresh stale age: 54 0 s 3600 s 剩下的新鮮時間 = 3600 - 54 = 3546 s
副本在 age 到達 max-age 之前都是新鮮的,剩下的時間就是 max-age 減掉 age。
  • cache-control: public, max-age=3600:任何 cache 都可以保留這份副本 3600 秒。
  • age: 54:這份副本已經在某個 cache 裡放了 54 秒。
  • Stale:超過 max-age。如果副本是 age: 4000、max-age=3600,它一到手就已經過期。

過期了不是刪掉,而是去問

cache origin GET + If-None-Match: "32b7140e..." 304 Not Modified(沒有 body)ETag 相同 cache-control: max-age=3600→ 新 TTL (依序找:① s-maxage ② max-age ③ Expires) age: 0→ 已經用掉的秒數 200 + 新檔案ETag 不同
refresh 帶著 ETag 去問 origin,拿到 304 就重新計算新鮮時間,不用再傳一次檔案。
  • 這個動作叫做 refresh。拿到 304,副本不變,新鮮時間重新起算。304 沒有 body,但還是要跑一趟。
  • CDN 的設定可以蓋掉 origin 的值,例如固定 TTL 或設上限(三個地方都在設定 TTL)。
  • 304 帶的 Age 也算數:max-age=3600、age: 4000,refresh 完還是過期。

CDN 也會告訴瀏覽器剩下的時間。我看過一個 script 回來是 max-age=2251,因為 CDN 的副本只剩 2,251 秒。後來我才知道,Age 太大的副本會讓下一層幾乎無法保留它(Stale-while-revalidate:先回舊檔,背景再刷新)。

前面的 cache,只會跟它收到的副本一樣新。

參考來源:RFC 9111: HTTP Caching

延伸閱讀:CDN 是什麼、Cache header:誰設定,誰讀取、三個地方都在設定 TTL、Stale-while-revalidate:先回舊檔,背景再刷新。或回到系列總覽。

↑↓ 移動 ↵ 開啟 esc 關閉