簡易筆記:瀏覽器快取策略

龍泉_springlong發表於2019-03-04

HTTP頭資訊

首先我們從資源被請求時,請求行為和資源快取的不同來看下HTTP頭資訊的表現:

資源的首次請求:

簡易筆記:瀏覽器快取策略

頁面重新整理-資源快取未過期:

簡易筆記:瀏覽器快取策略

頁面重新整理-資源快取已過期-資源未變更:

簡易筆記:瀏覽器快取策略

頁面重新整理-資源快取已過期-資源已變更:

簡易筆記:瀏覽器快取策略

資源被再次請求時-快取未過期:

簡易筆記:瀏覽器快取策略

快取策略

當瀏覽器請求資原始檔時,預設會將源資檔案快取到本地以便重複使用,加快網頁的載入速度。

瀏覽器的資源快取分為 from disk cachefrom memory cache 兩類。當首次訪問網頁時,資原始檔被快取在記憶體中,同時也會在本地磁碟中保留一份副本。當使用者重新整理頁面,如果快取的資源沒有過期,那麼直接從記憶體中讀取並載入。當使用者關閉頁面後,當前頁面快取在記憶體中的資源被清空。當使用者再一次訪問頁面時,如果資原始檔的快取沒有過期,那麼將從本地磁碟進行載入並再次快取到記憶體之中。

伺服器可以通過Response Headers使用 expirescache-control 設定一個有效的過期時間,當瀏覽器再次請求資源時會判斷本地快取是否已過期:

  1. 如果沒有過期那麼直接從本地快取讀取,不會產生http請求,此為 強快取
  2. 如果已過期,那麼瀏覽器將重新向伺服器請求資源,這一過程往往伴隨著 快取檢測

expires

這是HTTP1.0版本的產物,屬於 Response Headers,使用一個UTC格式的日期時間字串表示資源的過期時間。

使用 expires 設定的過期時間是以伺服器時間為準的,它可能跟瀏覽器時間不一致,不同時區也會存在影響。

cache-control

這是HTTP1.1版本的產物,屬於 Response Headers,提供更多詳細的快取策略,可以根據三種不同性質通過逗號進行組合使用:

  1. 是否不使用快取: cache-control: no-store/no-cache/must-revalidate
  2. 是否為私有快取: cache-control:public/private
  3. 設定過期時間: cache-control: max-age/s-maxage

是否不使用快取:

  1. must-revalidate : 當本地的資源快取沒有過期前,使用本地快取;當本地資源快取已過期時,需要進行快取檢測(預設值)。
  2. no-cache : 不管本地的資源快取是否過期,都需要進行快取檢測。
  3. no-store : 禁止瀏覽器快取資源,每次請求資源都去伺服器重新下載。

是否為私有快取:

  1. public : 公共快取,表示瀏覽器和代理伺服器都可以設定快取(預設值)。
  2. private : 私有快取,僅瀏覽器設定快取。

設定過期時間:

  1. max-age:使用 cache-control: max-age=60 的形式表示本地快取的資源將在xx秒之後過期,單位為秒,會覆蓋 Expires 的設定。
  2. s-maxage : 使用方式同 max-age ,在public設定下有效,針對共享快取(代理伺服器)有效。

使用 max-age 的優點在於設定的過期時間是一個相對於瀏覽器的時間,不受伺服器和瀏覽器時間不一致的影響,也不會因為時區的不同而受到影響。

啟發式快取

當資原始檔的 Response Headers 中帶有 last-modified 欄位,但是卻缺少 expirescache-control 用來表示資源快取的過期時間的欄位,這個時候瀏覽器會使用啟發式快取來確認該資源快取的過期時間:

瀏覽器會根據 datelast-modified 之間的時間差值的10%來作為資源快取的過期時間。

快取檢測

當瀏覽器重新向伺服器請求資源時,如果原先的 Response Headers 中存在 last-modified 或者 etag 資訊,那麼在 Request Headers 中會通過 if-modified-sinceif-none-match 將之前的資訊帶給伺服器進行檢測。如果伺服器資源相對於本地的資源快取沒有發生變更,那麼將會返回304狀態碼,表示資源未更新,讓瀏覽器使用本地的資源快取,這就是 協商快取

如果原先的 Response Headers 中沒有 last-modifiedetag 資訊,那麼將從伺服器重新下載資原始檔。

last-modified 和 if-modified-since

這兩個欄位都是HTTP1.0版本的產物。

  1. last-modified: 屬於 Response Headers,表示資源最後一次修改的時間。

  2. if-modified-since: 屬於 Request Headers,用來判斷伺服器端資源是否在該傳遞的時間之後做了修改,如果沒有修改那麼伺服器將返回304狀態碼,讓瀏覽器使用資源快取。

etag 和 if-none-match

這是HTTP1.1版本的產物。

  1. etag: 屬於 Response Headers,表示資源的唯一識別符號,由伺服器端生成。

  2. if-none-match: 屬於 Request Headers,用來判斷伺服器資源是否與該傳遞的識別符號不一致,如果一致則表示資原始檔沒有修改過,伺服器將返回304狀態碼,讓瀏覽器使用資源快取。會覆蓋 if-modified-since 的設定。

使用etag來判斷伺服器端資原始檔是否做了修改,主要有以下考慮:

  1. last-modified 只能精確到秒,而有些伺服器資源可能在1秒內進行了多次修改。
  2. 伺服器資原始檔,有些會定時自動生成,但是檔案內容並沒有發生任何變更。

使用者行為

瀏覽器的快取策略還跟使用者的行為有關:

  1. 當使用者從url位址列回車訪問網頁時,強快取和協商快取都有效。
  2. 當使用者從頁面中點選一個超連結訪問網頁時,強快取和協商快取都有效。
  3. 當使用者按F5重新整理時,強快取將無效,但會觸發協商快取。不過在Firefox瀏覽器中,強快取和協商快取均無效。
  4. 當使用者按Ctrl+F5強制重新整理時,強快取和協商快取都將無效,瀏覽器將向伺服器重新並下載資原始檔。

demo檢驗

為了徹底搞清楚瀏覽器的快取策略,這裡提供了一個使用node http模組構建的一個簡單伺服器環境,通過自行設定Response Headers來預覽瀏覽器快取的表現行為。點選下載資源包

下載資源包後,自行解壓,然後使用 npm install 命令安裝依賴,通過 node server 執行目錄下的server.js檔案來啟動本地伺服器,將會自動使用預設瀏覽器開啟目錄下的 /pages/index/index.html 頁面。

之後可以在cache.json配置檔案的下圖所示的程式碼中,對瀏覽器快取涉及到的四個http欄位進行編輯,修改完畢後儲存並強制重新整理瀏覽器頁面即可:

簡易筆記:瀏覽器快取策略

簡易筆記:瀏覽器快取策略

編輯說明:

  1. 設定相關欄位為false,則表示不設定相應的http欄位;
  2. 對於Cache-Control欄位的值,填寫其支援的策略組合即可;
  3. 對於Expires欄位的值,按秒填寫數字即可;
  4. 對於Etag和Last-modified欄位的值,設定為true即可;

參考資源

  1. 徹底理解瀏覽器快取機制
  2. 透過瀏覽器看HTTP快取
  3. 瀏覽器快取機制剖析
  4. 徹底弄懂 Http 快取機制 - 基於快取策略三要素分解法
  5. web效能優化之:no-cache與must-revalidate深入探究
  6. 由memoryCache和diskCache產生的瀏覽器快取機制的思考

相關文章