緩存是一種可以幫助網絡連接更快的技術,因為需要傳輸的東西越少越好。
許多資源可能非常大,檢索的時間和實際成本(例如,在移動設備上)都非常昂貴。
HTTP緩存是用于減少HTTP請求次數和提高Web應用程序性能的重要技術。Web瀏覽器和Web服務器可以通過HTTP頭控制HTTP緩存。
以下是HTTP緩存的一些重要概念:
無緩存
首先,Cache-Control header 可以通過使用 no-cache 值,告訴瀏覽器在不首先檢查 ETag 值(稍后將對此進行詳細介紹)的情況下永遠不要使用資源的緩存版本:
Cache-Control: no-cache
更嚴格的 no-store 選項告訴瀏覽器(以及所有中間網絡設備)不將資源存儲在其緩存中:
Cache-Control: no-store
如果 Cache-Control 有 max-age 值,則該值用于確定此資源作為緩存有效的秒數:
Cache-Control: max-age=7200
Expiresheader
當發送 HTTP 請求時,瀏覽器根據所需的 URL 檢查緩存中是否有該頁面的副本。
如果有,它會檢查頁面的新鮮度。
如果 HTTP 響應 Expires header 值小于當前日期時間,則頁面是最新的。
Expires header 采用以下形式:
Expires: Tue, 04 Oct 2022 19:00:00 GMT
強緩存
HTTP/1.0 使用的是 Expires header,HTTP/1.1 使用的是 Cache-Control header。
- Expires 即過期時間,時間是相對于服務器的時間而言的,存在于服務端返回的響應頭中,在這個過期時間之前可以直接從緩存中獲取數據,無需再次請求。但這種方式存在一個問題:無需再次請求服務器的時間和瀏覽器的時間可能并不一致。
- 在 HTTP/1.1 中,使用的是 Cache-Control header,這個 header 采用的時間是過期時長,對應的值是 max-age=*。
當 Expires 和 Cache-Control 同時存在時,優先考慮 Cache-Control header。當緩存資源失效了,也就是沒有命中強緩存,接下來就進入協商緩存。
協商緩存
如果緩存過期了,我們就可以使用協商緩存來解決問題。協商緩存需要請求,如果緩存有效會返回 304 Not Modified。
- 使用 If-Modified-Since 和 Last-Modified
- 使用 If-None-Match 和 ETag
所有這些都基于使用 If-* 請求頭,并且 ETag 優先級? Last-Modified 高。
If-Modified-Since和 Last-Modified
它添加一個 If-Modified-Since header,基于從當前緩存頁面獲得的 Last-Modified header 值。
Last-Modified 表示本地文件最后修改時間,If-Modified-Since 會將當前緩存頁面獲得的 Last-Modified 的 header 值發送給服務器,詢問服務器在該時間后資源是否有更新,有更新的話就會將新的資源發送回來。
否則,服務器將返回一個 304 Not Modified 響應。
這包括了發送的請求和頁面請求。
但是如果在本地打開緩存文件,就會造成 Last-Modified 被修改,所以在 HTTP/1.1 出現了 ETag。
If-None-Match和 ETag
web 服務器(取決于設置、頁面的服務方式等)可以發送 ETag header。
這是資源的標識符,類似于文件指紋。每次資源改變時,ETag 也應該改變。
它就像一個校驗和(checksum)。
瀏覽器發送一個 If-None-Match header,其中包含一個(或多個)ETag 值。發送到服務器后,詢問該資源 ETag 是否變動,有變動的話就將新的資源發送回來。
否則返回 304 Not Modified 響應。
Last-Modified 與 ETag 的對比
性能上,Last-Modified 優于 ETag,Last-Modified 記錄的是時間點,而 ETag 需要根據文件的 MD5 算法生成對應的 hash 值。
精度上,ETag 優于 Last-Modified。ETag 按照內容給資源帶上標識,能準確感知資源變化,Last-Modified 在某些場景并不能準確感知變化。
如果兩者都存在,優先判斷 If-None-Match 進行 ETag 協商緩存。
緩存位置
當命中強緩存和協商緩存返回 304 時,瀏覽器會從緩存中獲取資源。
瀏覽器中的緩存位置一共有四種,按優先級從高到低排列分別是:
- Service Worker — 其借鑒了 Web Worker 思路,主要功能有:離線緩存、消息推送和網絡代理,其中離線緩存就是 Service Worker Cache。
- Memory Cache — 內存緩存,從效率上講它是最快的,從存活時間來講又是最短的,當渲染進程結束后,內存緩存也就不存在了。
- Disk Cache — 存儲在磁盤中的緩存,從存取效率上講是比內存緩存慢的,優勢在于存儲容量和存儲時長。
- Push Cache — 推送緩存,它瀏覽器緩存的最后一道防線,它是 HTTP/2 的內容。
瀏覽器在選擇 Disk Cache 與 Memory Cache 的存儲上:內容使用率高的,文件優先進入磁盤。比較大的 JS、css 文件會直接放入磁盤,反之放入內存。
強緩存與協商緩存區別
- 強緩存 — 瀏覽器不會與服務端協商,而是直接獲取瀏覽器緩存。
- 協商緩存 — 瀏覽器會先向服務器確認資源的有效性后,才決定是從緩存中獲取資源還是重新獲取資源。
- 強緩存在瀏覽器進行判斷,而協商緩存在服務端進行判斷。