HTTP Caching
27 Jul 2018快取規則
- ETag:用來驗證檔案是否更新,若檔案未更新,則不回傳檔案。
- Cache-control:每個資源皆可設定 Response Headers 的 Cache-control 來定義快取策略。
- no-cache, no-store:主要用於決定是否要求更新檔案,no-cache 表示要求伺服器檔案時必須以 ETag 確認是否有更新檔案,若無更新,伺服器不需回應檔案;no-store 表示禁止儲存快取,每次都必須跟伺服器要求新檔案,適用於私人或機密資料。
- public, private, must-revalidate :可快取回應的使用者,public 表示可供所有中繼設備和瀏覽器快取,例如 ISP Cache、CDN 快取和瀏覽器快取;private 只限單一使用者快取,例如可供瀏覽器快取;must-revalidate 表示表示可使用快取檔案,但過期時必定要去伺服器驗證是否有新檔案。
- max-age:快取時限,以秒為單位,
max-age: 600
表示快取時限為 10 分鐘,10 分鐘後這個快取檔案就過期了,必須跟伺服器要求更新後的檔案。max-age 覆寫 expires header 的設定,讓 expires header 作為 fallback 機制。
範例如下,檔案可供所有設備快取,過期時間是兩年後。
如何決定要使用快取還是取得更新資源?
流程如下圖。
說明
- A:client 端準備發出 HTTP request 要求資源
- B:檢查 local cache 是否有此資源,若沒有這個資源,則到 C;若有這個資源,則到 E
- C:由於 local cache 沒有這個資源,因此直接跟 server 端要求資源
- D:承 C,跟 server 端成功要到資源,server 回傳檔案,status code 200
- E:承 C,由於 local cache 有這個檔案,但不確定能不能用、有沒有過期,因此要檢查過期條件 cache-control 與 last-modified。若沒有過期,則到 F;若過期了,則往 G
- F:承 E,由於沒有過期,因此可使用 local cache 的檔案,status code 200 (from memory/disk cache)
- G:承 E,由於過期了,於是從 client 端發出 HTTP request 要求資源
- [方案一,在這裡想要更進一步確認檔案內容的確有更動,所以不用這個方案] 使用 if-modified-since 要求更新後的資源,詢問 server 端要求指定時間後更新的資源
- [方案二,在此圖是用這個方案] 使用 etag 判斷檔案內容是否有更動,若有更動則使用 if-none-match 詢問 server 端索取新資源
- H:承 G,若檔案沒有更動,則往 I;若有更動,則往 J
- I:承 H,不回傳檔案,status code: 304 not modified
- J:承 H,回傳新版檔案,status code: 200
如何強迫瀏覽器更新資源?
方法一,變更資源的網址,例如加入 hash。相同網址之下,會讀取本地快取,所以改變網址即可,可解決資源未過期但想要更新的狀況。
以下三個網址對瀏覽器來說都是不一樣的,不會讀取本地快取,會重新要求資源。
https://www.sample.com.tw/assets/cute.png
https://www.sample.com.tw/assets/cute.png?123
https://www.sample.com.tw/assets/cute.v123.png?123
方法二,使用 ctrl + F5
或 ctrl
並點擊瀏覽器的更新按鈕來強制更新,重新向伺服器請求所有資源,而不使用快取,因此可取得最新版本的內容。
Checklist
- 統一網址格式,避免同一資源因不同網址而多次取得或重複快取此資源內容。
- 在伺服器端為資源設定 ETag,讓資源未更新時不需回應。
- 決定資源可快取的使用者,例如 public 或 private,是否可被中繼設備快取?私密資訊只允許讓私人快取?
- 決定資源快取期限。
- 決定快取條件,例如 no-cache、no-store 或加入 hash 改變資源網址以強迫更新資源。
- 確定資源經過最佳化,以減少更新資源的成本。
範例
資源未被快取。
資源來源是記憶體快取。
資源來源是 HTTP 快取(HTTP Cache)又稱為磁碟快取(Disk Cache)。
資源來源是記憶體快取,但使用 Hash 控制是否要強迫瀏覽器更新資源。
資源經 ETag 確認未更新,因此使用快取檔案。
對於各種快取的說明,可參考這篇,內含記憶體快取、Service Worker 快取、HTTP 快取和 Push 快取。