0%

cache 概念整理

cache 功用

相同的資料不用重新抓,省時省流量

cache 設定

Stop using (HTTP 1.0) Replaced with (HTTP 1.1 since 1999)
Expires: [date] Cache-Control: max-age=[seconds]
Pragma: no-cache Cache-Control: no-cache

http 1.0 的快取方式

  • Pragma
  • Expires

為了兼容,大部分網站還是會放

Pragma: 禁用快取

1
2
3
4
// 直接放在 meta 標籤中
<meta http-equiv="Pragma" content="no-cache">
// 放在 response header
Pragma: no-cache

no-cache: 告訴客戶端不要對該資源快取

但受限於僅 IE 可用、僅限頁面而頁面上資源不受影響,基本上沒什麼用

與 Cache-Control: no-cache 功能一樣

Expires: 啟用快取並設定快取時間

1
2
3
<meta http-equiv="expires" content="mon, 18 apr 2016 14:30:00 GMT">
...
Expires: Fri, 11 Jun 2021 11:33:01 GMT

若 Pragma 和 Expires 同時出現,則 pragma 優先級更高

http 1.1 新增 Cache-Control

由於 expire 無法保證 client 端時間和 server 端時間統一,http 1.1 新增 Cache-Control

若同時出現 Pragma、Expires 和 Cache-Control,Cache-Control 優先級更高

此部份分成三種快取方案

  1. 資源是否要快取
  2. 快取多久
  3. 到期後如何判斷是否過期

資源是否要快取

1
cache-Control: no-store/no-cache
  • no-store: 每次都去 server 要新資料,不存任何快取

  • no-cache: 快取需存取,但每次都去 server 檢查快取

  • 沒有提供: 都存

  • private: 只有 client 可以存快取,proxy 不行

  • public: 大家都可以存

快取多久

1
Cache-Control: max-age=31536000

max-age 與 expire 都是決定要快取多久,在時間以內則直接使用快取

browser 使用快取回應 Status code 200 (from memory cache)

注意 no-cache 不能和 max-age 一起搭配使用,no-cache 行為上與 max-age=0 相同,等於此資源在使用快取前須去 server 檢查有沒有新版本,不過還是有差

沒有設定 max-age 或 expire 的話

  • 有設定 Last-Modified: expire = 當前時間+(request date-lastModified) * 10%
  • 也沒有設定 Last-Modified: 都沒有= =就存不住阿

from memory cache vs from disk cache

到期後如何判斷是否過期

當 browser 判斷快取已過期(max-age 時限超過),則會發 requet 跟 server 要新檔案

但是要是該檔案根本沒更新,可以繼續使用原來的快取呢?

這時就會用到 Last-Modified 與 ETag 來判斷檔案的是否更新

Last-Modified

當第一次清求資源時,response header 會設定 Last-Modified

1
Last-Modified: Fri, 25 Feb 2021 01:47:00 GMT

當第二次請求該資源,則 request 會帶上 If-Modified-Since

1
If-Modified-Since: Fri, 25 Feb 2021 01:47:00 GMT

如果該時間與 server 中該資源的最後修改時間一致,表示沒有修改過,server 返回 304 Not Modified,若有修改過,則回傳新版本的檔案

小問題: 檔案如果被打開,但是在沒有修改的情況下存檔,則會更新檔案最後修改時間,這時就要用 etag 判斷

ETag

Etag 會根據檔案內容、長度等等資訊計算出 hash 值,不同 server 會有不同計算方法

在資源回傳給 client 時,response header 會設定 Etag

1
Etag: "5d8c72a5edda8d6a:3239"

下次請求該資源時,request header 會帶上 If-None-Match

1
If-None-Match: "5d8c72a5edda8d6a:3239"

如果該資源比對後 etag 若一致,則回傳 304,不一致則回傳新版本的檔案

如果同時設定 Last-Modified 與 ETag,ETag 的優先權更高

我要最即時的更新! 但是我又不想一直問有沒有新版本

以上設定雖然可行,但是有沒有可能 「只要檔案不更新,瀏覽器就不會發 Request,直接沿用快取裡的即可。只要檔案一更新,瀏覽器就要立即抓取新的檔案」(by Huli)

只要將 ETag 實作在檔案上 + max-age 即可做到,通常前端框架 build 完都會幫你加上類似 etag 的副副檔名(那個專有名詞是啥==a)

1
<script src='script.66666.js'></script>
1
Cache-Control: max-age=31536000

推薦快取策略

好圖推薦,不過原圖似乎被撤掉了

(來源:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-tw)

參考資料

循序漸進理解 HTTP Cache 機制

浅谈浏览器http的缓存机制

HTTP缓存控制小结

彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法