深入現代瀏覽器的HTTP快取機制

Wongzw發表於2019-04-02

前言

寫這篇文章的原因是最近在研究PWA如何在專案中落地實施,這就無可避免的需要接觸到瀏覽器快取的相關知識,因此特意寫下這篇文章鞏固下自己對瀏覽器快取的認識。

什麼是HTTP快取

快取是一種儲存資源副本並在下次請求時直接使用該副本的技術。當web快取發現請求的資源已經被儲存,它會攔截請求,返回該資源的拷貝,而不會去源伺服器重新下載。這樣帶來的好處有:緩解伺服器端壓力,提升效能(獲取資源的耗時更短了)。

HTTP快取的作用

我們都知道瀏覽器是基於HTTP協議和服務端進行通訊的,一個網站一旦同時請求過多或者請求過大就容易造成頁面渲染時長過長等效能問題,而且並非所有資源都需要實時更新的,將長久或一段時間內的資源進行快取,能很大的緩解伺服器壓力和提升網站效能。
毫不誇張的說,HTTP快取是達到高效能的重要組成部分。

注意:快取需要合理配置,因為並不是所有資源都是永久不變的:重要的是對一個資源的快取應截止到其下一次發生改變(即不能快取過期的資源)。

HTTP頭快取相關欄位及優先順序

強快取:Expires: Date/Cache-Control:max-age=N
協商快取:Last-Modified:DateEtag:String

通過查詢標準我們知道Cache-Control和Etag屬於HTTP1.1版本,Expires和Last-Modified屬於HTTP1.0版本,所以得出以下優先順序:
強快取:Cache-Control > Expires
協商快取:Etag > Last-Modified

注意:
Expires存在的缺陷是返回的到期時間是伺服器端的時間,可能與客戶端的時間有較大的時間差,所以在HTTP1.1版開始使用Cache-Control: max-age=秒替代
Last-Modified的缺陷:由於只能精確到秒,如果一個檔案在1秒內多次修改,這時客戶端無法識別,因此HTTP1.1版本使用Etag標識資源內容是否有變更來確認資源是否需要更新,相對來說更加精確

強快取與協商快取

強快取:資源一旦被強快取,在快取時間內,瀏覽器發起二次請求時會直接讀取本地快取,不與伺服器進行通訊。 強快取時間過期的,瀏覽器會判斷資源的響應頭是否有Last-Modified和Etag欄位,有的話執行協商快取策略

協商快取:如果響應頭中的包括有Etag和Last-Modified欄位,則客戶端將If-None-Match:Etag的值和If-Modified-Since:Last-Modified的值新增到請求頭髮送給伺服器,由源伺服器校驗,如果資源未過期則返回304狀態碼,瀏覽器直接使用快取,否則返回200OK狀態碼和新資源。

當兩種情況都存在時,強快取優先順序要高於協商快取

Chrome瀏覽器的三種快取策略

選擇Chrome是因為它是現在最流行的網頁除錯工具也是最多人用的瀏覽器。 Chrome瀏覽器返回快取http狀態碼總共有以下三個 1、200 from memory cache 客戶端不與伺服器通訊,直接從記憶體中讀取快取。此時的資料時快取到記憶體中的,當關閉瀏覽器後,資料自然就被當垃圾回收清空。

2、200 from disk cache 客戶端不與伺服器通訊,直接從磁碟中讀取快取,因為資料存在磁碟中,就算關閉瀏覽器資料還是存在,下次開啟只要資料不過期就可以直接讀取。

3、304 Not Modified 客戶端與伺服器通訊,伺服器驗證資源是否需要更新,如果不需要更新伺服器返回304狀態碼,然後客戶端直接從快取中讀取資料

注意:經過測試,我發現Safari和Firefox都有三種快取策略,IE和其他瀏覽器大家可以各自測試一下

瀏覽器三種快取示例圖

Chrome和Safari似乎沒有辦法在瀏覽器中直接檢視快取情況,因此只能實踐中檢視。 Chrome示例圖: 狀態碼:200 OK

深入現代瀏覽器的HTTP快取機制
狀態碼:200 from memeory cache
深入現代瀏覽器的HTTP快取機制
狀態碼:200 from disk cache
深入現代瀏覽器的HTTP快取機制
狀態碼:304 Not Modified
深入現代瀏覽器的HTTP快取機制

Safari示例圖: 響應頭:

深入現代瀏覽器的HTTP快取機制
狀態碼:200 OK
深入現代瀏覽器的HTTP快取機制
狀態碼:200 記憶體
深入現代瀏覽器的HTTP快取機制
狀態碼:200 磁碟
深入現代瀏覽器的HTTP快取機制

Firefox:在url上輸入about:cache 可以看到對應的快取情況,大家可以試一下

深入現代瀏覽器的HTTP快取機制
從截圖中可以看到Firefox也分為記憶體快取和磁碟快取,304Not Modified自然也是有的。
深入現代瀏覽器的HTTP快取機制
資源被強快取後狀態碼依然是200 OK,不過會在傳輸列下顯示已快取,但是無法看出是記憶體快取還是磁碟快取。
深入現代瀏覽器的HTTP快取機制
Firefox的304與Chrome和Safari差別不大。

三種快取策略實際執行的條件

我在網上看到有人寫文章說 js、圖片和字型儲存在記憶體中而css則儲存在磁碟,很明顯,只要自己稍微測試一下就知道這種說法是站不住腳的,那麼這三種情況究竟是怎樣的呢?

經過簡單的測試以後我發現這三種策略並不複雜,預設配置情況下,Chrome第一次請求資源後,如果資源的響應頭有Cache-Control或者Expires且有效期大於現在,則載入資料後將強快取資源到記憶體和磁碟。
重新整理頁面,Chrome發起整個頁面的二次請求後,通過開發者工具可以看到強快取資源都會從記憶體進行讀取,這就是200 from memory cache的情況。

示例:
這時關閉瀏覽器後,重新開啟瀏覽器並開啟關閉前的頁面,通過開發者工具可以看到之前強快取資源都會從磁碟中讀取,這是因為關閉了瀏覽器後系統回收了記憶體資源,因此記憶體沒有了之前的強快取資源,需要從磁碟中讀取,這就是200 from disk cache的情況。

示例:
如果這時使用ctrl + f5強刷頁面則會發現全部資源都是200 OK狀態要從伺服器中獲取新資料。

304 Not Modified的情況則完全不同,如果資源的響應頭是Last-Modified或Etag,第一次請求資源後快取到本地磁碟,但第二次也必須發起請求到伺服器進行查詢該資源是否過期或被修改過,當伺服器驗證資源沒有過期後才會返回304 Not Modified狀態碼,同時響應體為空,這樣可以節省流量並提高響應速度,客戶端接收到304狀態碼後從本地讀取資料,因此304比200 from cache響應速度要慢,但比200 OK快得多。

Chrome瀏覽器快取機制流程圖

Chrome瀏覽器快取機制流程圖

上述說法均為個人想法,如有不對,敬請指出,謝謝大家的閱讀!

相關文章