1. 瀏覽器緩存簡介
1.1 什么是瀏覽器緩存
瀏覽器緩存是指: 將從服務器獲取的一些數據緩存到本地, 從而使得瀏覽器需要再次加載此數據時, 直接從計算機本地獲取數據, 而不是通過服務器獲取數據
1.2 為什么要有瀏覽器緩存
- 能夠提高用戶的體驗: 從本地獲取資源的速度一般情況下比從服務器獲取資源的速度要快幾個量級
- 能夠緩解服務器的壓力以及網絡壓力: 從本地獲取資源這一行為並不需要向服務器請求資源(除非本地緩存過期了), 服務器也不需要占用對應量的帶寬將數據傳輸回來
1.3 瀏覽器緩存資源的位置
- Memory Cache: 將資源緩存到內存中, 能夠緩存的量相對 Disk Cache 來說較少, 獲取資源的速度快於 Disk Cache, 但是關閉對應 Tab 后, 資源不會保存在內存中, 再次開啟對應頁面時不能從內存中獲取到相應資源
- Disk Cache: 將資源緩存到硬盤中, 能夠緩存的量相對 Memory Cache 來說更多, 獲取資源的速度慢於 Memory Cache, 但是關閉對應 Tab 后, 資源仍存在於硬盤中, 再次開啟對應頁面仍能獲取緩存
對於緩存位置:
- 較大的文件, 其會優先放到硬盤中, 反之, 較小的文件會優先放到內存中
- 如果內存使用率比較低, 就會優先將資源放到內存, 反之, 就會優先將資源放到硬盤
2. 瀏覽器緩存的類型
2.1 強緩存(強制緩存)
根據請求資源所對應的響應頭的 cache-control(HTTP/1.1) 和 expires(HTTP/1.0) 字段來進行設置
2.1.1 cache-control
- no-cache: 表示不設置強緩存, 但是仍可設置協商緩存
- no-store: 表示不設置緩存(包括強緩存和協商緩存)
- max-age=233: 表示該緩存在 233 秒后過期, 在此期間, 可以從緩存中獲取該資源
- private: 表示該資源只能在客戶端被緩存, 不能被代理服務器緩存
- public: 表示該資源可以被客戶端和代理服務器緩存
2.1.2 expires
- Mon, 01 Nov 2021 03:24:05 GMT: 表示該資源在格林威治時間 2021年11月01日03:24:05 時過期, 在此之前, 可以從緩存中獲取該資源
- 局限(為什么要使用 cache-control): 受限於本地時間, 如果本地時間和服務器的時間不相符, 則緩存可能達不到服務器所預想的效果
瀏覽器在請求服務器資源之前, 會先看看強緩存中是否有該資源(一般非 HTML 文件都會被強緩存), 且沒有過期
- 若存在該資源, 且沒有過期: 則返回狀態碼 200 和該資源
- 若不存在該資源, 或過期了: 啟用協商緩存
2.2 協商緩存(強緩存不命中時啟用)
根據請求資源所對應的響應頭的 etag/if-none-match(HTTP/1.1) 和 last-modified/if-modify-since(HTTP/1.0) 字段來進行設置
2.2.1 etag/if-none-match
服務器響應時, 返回當前資源的一個唯一標識 etag(由服務器生成), 而瀏覽器則在緩存資源的同時記錄 etag 的值.
- 當需要從協商緩存中獲取該資源時, 瀏覽器將記錄的 etag 值作為 if-none-match 字段的值加入 requset header 中, 並發送給服務器
- 若發送的 if-none-match 與服務器中資源對應的標識相同, 則說明服務器的資源與客戶端協商緩存的資源相同, 服務器返回 304 表示資源沒有被修改. 客戶端收到響應, 直接使用本地資源
- 否則, 服務器重新發送資源給客戶端, 客戶端重新緩存該資源
2.2.2 last-modified/if-modify-since
last-modified 的格式與 expires 的格式一樣, 都是一個時間, 只不過這個時間指的是對應資源最后一次更新的時間
- 當瀏覽器請求對應資源時, request header 中會包含 if-modify-since, 其值為 last-modified, 服務器收到 request 之后, 通過檢查 if-modify-since 來判斷是否需要重發資源
- 若不需要重發資源, 則直接發送一個 304 狀態碼, 客戶端繼續使用緩存的資源
- 否則, 服務器重新發送資源給客戶端, 客戶端重新緩存該資源
- 局限(為什么要使用 etag/if-none-match):
- last-modified 只能精確到秒, 如果一個資源在 1s 內發生了變化, 服務器就會判斷出錯, 從而導致瀏覽器使用錯誤的資源
- 如果某個資源的內容沒有發生改變, 但是它的修改時間又發生了變化, 那么服務器也會重新發送該資源