web 前端基礎:瀏覽器的緩存機制


web 前端基礎:瀏覽器的緩存機制


前言

掌握緩存策略,對提高前端頁面的性能有非常大的幫助,同時也能減少服務端的壓力。

同時,這也是前端面試中常問的問題,不管怎麼樣,這系列知識點在實戰應用中很重要,需要理解透徹。

下面講下,緩存中的強緩存協商緩存。(備註,服務端均由 Express 提供服務)


web 前端基礎:瀏覽器的緩存機制


強緩存

Expires

服務端給客戶端設置的 Expires 過期時間響應頭,客戶端下次再次請求時,會通過本地時間和該時間做對比。

如果本地時間大於 Expires 設置的時間,將重新向服務端獲取資源。

下圖,服務器設置了1小時的緩存,當客戶端再次請求資源時,http 狀態碼為 200,但能看到 from memory cache 的提示(證明資源文件是從本地拿的):

web 前端基礎:瀏覽器的緩存機制

Expires 示意

代碼示意:

express.static 是由 serve-static 提供基礎功能的,幫助我們快速設置緩存相關選項。

這裡著重看下紅框內容,如何設置 Expires 響應頭:

web 前端基礎:瀏覽器的緩存機制

express.static 配置


Expires 似乎解決了緩存問題,但光光靠它遠遠不夠,最起碼我們現在看到他有這些不足:

  • 服務端需要設置一個固定的 Date 時間
  • 強依賴客戶端時間,我們知道本地時間是可以修改的,會導致緩存失效等問題



題外話:

這裡注意到 UTC 時間格式,主要為了區別 GMT,如果沒有設置的話,將是這樣(多 8 個小時):

web 前端基礎:瀏覽器的緩存機制


另外,關於時區 timezone 問題,可以參考 sequelize moment-timezone 之間的處理(題外話,可能部分同學會遇到類似問題,這裡帶到下):

web 前端基礎:瀏覽器的緩存機制

sequelize 時區處理


web 前端基礎:瀏覽器的緩存機制

sequelize 時區處理



Cache-Control

當我們開啟 express static 的 cacheControl 默認配置,能看到 Expires 失效了。

web 前端基礎:瀏覽器的緩存機制

Cache-Control 默認開啟


web 前端基礎:瀏覽器的緩存機制

覆蓋 Expires


默認 max-age 為 0 ,但這已經證明一點:Cache-Control 的優先級高於 Expires。

我們可以對 max-age 專門設置一個增量的緩存時間:

web 前端基礎:瀏覽器的緩存機制

設置 maxAge

這樣客戶端每次請求在這個時間範圍內,就屬於緩存,也就不會向服務器請求資源了。



緩存參數

Cache-Control 還涉及 no-cache/no-store 和 public/private 等具體參數:

  • public:整個網絡請求中的任何中間層都可以緩存資源
  • private:對比 public,只有客戶端可以緩存資源
  • no-cache:交給服務端判斷是否要緩存,跳過強緩存,走入下一環節:協商緩存
  • no-store:不緩存,每次都從服務器獲取資源

協商緩存

200 和 304

首先要搞清一個問題,什麼時候瀏覽器請求資源的 http 狀態碼會返回 200 或者 304。

上述的強緩存都會查看本地環境,驗證緩存狀態,如果沒過期,也會響應 200,只是要注意後面的備註信息(from disk、from memory)。

相反,如果設置了 no-cache 等協商緩存,本地緩存就會忽略,向服務器驗證資源是否有更新,沒更新則返回 304。


web 前端基礎:瀏覽器的緩存機制

304 http 狀態碼示意


Last-Modified

Last-Modified 是服務器端設置的響應頭,返回請求資源對應的服務器資源文件的修改時間戳。用於驗證資源文件是否被修改過。精度比 ETag 低。


web 前端基礎:瀏覽器的緩存機制

Last-Modified 修改文件後,http 狀態碼


示例

注意,express 中:默認 Last-Modified 和 Etag 是打開的。

首次請求時,如果服務器設置了 Last-Modified 請求頭,則會把請求資源文件的最後次修改時間戳返回:

web 前端基礎:瀏覽器的緩存機制

Last-Modified 示意

當我嘗試服務器端修改該文件後,再次請求改文件,時間戳為最新一次,可以對比前後時間的不同

web 前端基礎:瀏覽器的緩存機制

注意響應時間的更改

當本地沒有緩存時,會向服務器請求資源,同時會增加額外的 If-Modified-Since 請求頭,以讓服務器做判斷。

如果服務器資源沒有更新過,則會響應 304 狀態碼,並不會發送資源文件(能看到沒有 Content-Length):

web 前端基礎:瀏覽器的緩存機制

反之,如果服務器資源文件更新過,則請求頭中的

If-Modified-Since 和服務器資源文件的時間戳將會不一致,服務器判斷後會響應資源。同時服務器將響應 200 狀態碼,且發送資源文件:

web 前端基礎:瀏覽器的緩存機制


缺點

服務器資源文件管理問題,導致服務器緩存失效:

因為服務器資源文件只要更新/修改過,其文件時間都會更新。如果因為發佈,或者其他原因導致這樣的變化,則會讓服務器響應沒必要的更新。(因為文件內容沒有變化過)


Etag

彌補 Last-Modified 的一些不足之處,為服務器資源文件生成一個"指紋"值,用於精確對比文件更新狀態。


首次請求後,服務器會給客戶端一個 Etag 值,下次請求時將以 If-None-Match 向服務器傳送客戶端 tag 值,如果服務器判斷一致,則相應 200,否則 304。

上例中,已經的圖例中已經涉及了 Etag 場景,注意對比兩個 Etag "指紋"值:

web 前端基礎:瀏覽器的緩存機制


幾種刷新操作對比


web 前端基礎:瀏覽器的緩存機制

幾種刷新操作對比


總結

簡單說了幾種緩存相關的概念,具體運用還是要具體分析,配合前端工程化一系列的構建輸出,友好的和緩存機制共存是個時刻要磨合的。(大廠都有一套"完美"的最佳實踐,但對於我來說還需要積累經驗)


分享到:


相關文章: