案例解讀:深入理解瀏覽器的快取機制

摘要:快取可以減少網路 IO 消耗,提高訪問速度。瀏覽器快取是一種操作簡單、效果顯著的前端性能優化手段。

前言

瀏覽器快取是前端性能優化的重要一環,對於前端效率提升的重要性,不言而喻。

之前對於瀏覽器快取也是一知半解,這次借著H5頁面快取優化的東風整理了一下本地瀏覽器端的快取機制,如強制快取、協商快取等,並且然後結合門戶域各部件(官網、雲社區、雲市場、個人中心、APP)當前的快取機制進一步分解,旨在呈現下當前華為雲官網的快取策略,供大家參考。

1 瀏覽器快取

1.1 瀏覽器快取

快取是一種本地保存遠端資源的機制,不管是在客戶端、還是在服務端存儲著,用相同的URL進行數據請求,可以直接從快取中請求資源而不再訪問源伺服器。

Web前端快取大致可以分為:資料庫快取、伺服器端快取(代理伺服器快取、CDN快取)、瀏覽器快取。

瀏覽器快取也包含很多內容:HTTP 快取、indexDB、cookie、localstorage 等等。這裡我們只討論 HTTP 快取相關內容。

1.2 瀏覽器快取的意義:

瀏覽器在本地對用戶對最近請求過的文檔進行存儲,當用戶再次訪問同一頁面時,瀏覽器就可以直接從本地磁碟載入文件。瀏覽器快取的意義主要在:

a. 避免了冗餘的數據傳輸,節省流量;

b. 加快了用戶訪問網頁的速度;

c. 減小了伺服器的壓力。

2 快取類型

2.1 第一次請求數據

瀏覽器第一次請求數據時,瀏覽器快取中沒有對應的快取數據,此時需要請求伺服器,瀏覽器返回數據後,會把請求的數據存儲至快取資料庫中。

當瀏覽器中存在快取數據後,可以根據是否需要向伺服器發送請求,將快取類型分為:強制快取和協商快取。

2.2 強制快取

用戶請求數據,如果命中強快取,則不向伺服器請求,而直接從本地資源獲取,返回200狀態碼,並提示from disk cache或from memory cache(比從disk快)。

2.3 協商快取

在用戶請求資源時,瀏覽器直接向伺服器發送請求,協商對比服務端和本地的資源,驗證本地資源是否失效。

2.4 強制快取和協商快取的關係

強制快取和協商快取命中快取資源後,都是從本地讀取資源。如果強制快取生效,則不需要再向伺服器發出請求;而協商快取,不管是否使用快取,必須向伺服器發送一個請求來協商。

兩類快取規則可以同時存在,強制快取優先順序高於協商快取,也就是說,當執行強制快取的規則時,如果快取生效,直接使用快取,不再執行協商快取規則。如果強制快取規則不生效,則需要進行協商快取判斷。

3 快取相關header

上文介紹了強制快取與協商快取的流程,那麼在瀏覽器中,瀏覽器如何判定快取數據是否失效呢?如何確認是否使用快取數據呢?

3.1 強制快取

強制快取的response header中會有兩個欄位來表明失效規則(Expires/Cache-Control)

1. Expires:Expires的值為服務端返回的到期時間,即下一次請求時,請求時間小於服務端返回的到期時間,直接使用快取數據。不過Expires 是HTTP 1.0的東西,現在默認瀏覽器均默認使用HTTP 1.1,所以它的作用基本忽略。另一個問題是,到期時間是由服務端生成的,但是客戶端時間可能跟服務端時間有誤差,這就會導致快取命中的誤差。 所以HTTP 1.1 的版本,使用Cache-Control替代。

2. Cache-Control:Cache-Control 是最重要的規則。常見的取值有private、public、no-cache、max-age,

Expires和Cache-Control的關係:

a. 相同點:兩者都是強快取。

b. 不同點:

  • Expires是http1.0規定的,而Cache-Control是http1.1規定的。
  • Expires的過期時間採用的是絕對時間,容易造成差錯; 而Cache-Control的過期時間採用的時相對時間,在快取上不會出現問題。
  • 兩者可以同時存在於一次請求中,但是不會同時在一次請求中起作用。 在HTTP1.0的環境下,Cache-Control不起作用,Expires起作用; 在HTTP1.1的環境之下, Expires不起作用,而Cache-Control起作用。當前一般都是http1.1的情況,所以Expires是作為一種向下兼容的形式而存在的。
  • Cache-Control的選擇更多,功能更為強大,推薦使用。 Expires作為強快取,功能單一,不推薦使用。

例如:下圖(華為雲官網首頁)中,文件global.js的Cache-Control指定的快取失效時間max-age為86400s(1天):

3.2 協商快取

協商快取一般是使用 if-modified-since/Last-Modified 和 if-none-match/Etag 由伺服器來決定瀏覽器快取的資源是否可以使用。

1. Last-Modified / If-Modified-Since

Last-Modified:伺服器響應請求時,告訴瀏覽器資源最後的修改時間。

If-Modified-Since:瀏覽器再次請求資源時,瀏覽器通知伺服器,上次請求時,返回的資源最後修改時間。

若最後修改時間小於等於If-Modified-Since,則response header返回304,告知瀏覽器繼續使用所保存的cache。若大於If-Modified-Since,則說明資源被改動過,返回狀態碼200;

2. If-none-match / Etag

Etag:伺服器響應請求時,告訴瀏覽器當前資源在瀏覽器的唯一標識(生成規則由伺服器確定)

If-None-Match:再次請求伺服器時,通過此欄位通知伺服器客戶端快取數據的唯一標識。伺服器收到請求後發現有If-None-Match 則與被請求資源的唯一標識進行比對,不同,說明資源又被改動過,則響應整片資源內容,返回狀態碼200;相同,說明資源無新修改,則響應HTTP 304,告知瀏覽器繼續使用所保存的cache。

Etag與Last-Modified對比:

  1. 在精確度上,Etag優於Last-Modified。Last-Modified精確到s,如果1s內,資源多次改變,Etag是可以判斷出來並返回最新的資源。
  2. 在性能上,Last-Modified優於Etag,因為Last-Modified只需要記錄時間,而Etag需要伺服器重新生成hash值,所以性能上略差。
  3. 在優先順序上,Etag優於Last-Modified,Etag和Last-Modified可同時存在。本地快取時間到期後,瀏覽器向服務端發送請求報文,其中Request Header中包含If-none-match和Last-Modified-Since(與服務端Etag和Last-Modified對比,Etag優先順序高),用以驗證本地快取數據驗證是否與服務端保持一致。在伺服器端會優先判斷Etag。如果相同,返回304;如果不同,就繼續比較Last-Modified,然後決定是否返回新的資源。若服務端驗證本地快取與服務端一致,返回304,瀏覽器載入本地快取;否則,伺服器返回請求的資源,同時給出新的Etag以及Last-Modified時間。

3.3 快取請求

以下為瀏覽器快取的流程:

4 實例分析

對於客戶端來說,瀏覽器在使用本地快取數據時,需要對齊本地與伺服器的資源;但是,對於服務端,伺服器將資源下發給客戶端,服務端就失去了對齊的控制權。比如,服務端設定快取失效的max-age,在這段時間內,哪怕服務端資源已發生更改,服務端也無法通知客戶端資源更新通知。所以,對於一個網頁來說,需要合理的指定快取的廢棄與更新的響應策略,從而既能提升頁面載入速度,同時確保頁面的準確性。

以下結合華為雲官網各部件,分析快取的廢棄和更新的響應策略:

4.1 官網首頁:

注釋:

  • Html:快取有效時間為0s,頁面載入時,強制瀏覽器每次向源伺服器確認數據;
  • Css:改動頻率較低,允許使用本地快取,且存在強制快取時間(各個css文件不同,按需設置);強制快取失效再進行協商快取;
  • Js:允許使用本地快取,且存在強制快取時間(各個js文件不同,按需設置);強制快取失效再進行協商快取;
  • Image:圖片修改頻率更低,允許使用本地快取,且存在強制快取時間(各個image文件不同,按需設置);強制快取失效再進行協商快取;
  • Gif:官網中gif主要存在於banner輪播,因此確保時效性,使用no-cache,不允許快取,強制每次向源伺服器確認數據。

注意(以下已官網首頁為例,介紹快取與版本號的關係,其餘各部件都存在相同問題,後續不一一解釋。):

上圖描述的是可快取文件的快取策略。但是,網頁中還有很多文件,比如global.js、global.css等,更新頻率較快,如果一直使用本地快取可能會影響頁面的正確性。因此,在引用這部分文件時,會在文件後添加個版本號,用以刷新快取,以此確保本地資源的時效性,添加版本號的目的是為了強制要求文件每次載入重新向服務端請求。如下,左圖給出了部分文件的版本號後綴。這部分文件在瀏覽器重新載入後,請求報文的頭文件,Request Header的Cache-control值為no-cache,即無快取,重新請求數據。如下右圖所示:

4.2 社區

注釋:

  • Html:快取許可權為public;本地快取到期時間expires為固定Thu, 19 Nov 1981 08:52:00 GMT,也就是本地快取永遠是到期的;因此,每次載入頁面都需要重新向源伺服器獲取資源。
  • Css:改動頻率較低,允許使用本地快取,且強制快取時間為1天;強制快取失效再進行協商快取;
  • Js:允許使用本地快取,且強制快取時間為1天;強制快取失效再進行協商快取;
  • Image:圖片修改頻率更低,png格式文件允許使用本地快取,且強制快取時間為1周,jpg格式文件為一月; 本地快取到期後,會繼續通過判定Etag和Last-Modified,驗證本地快取的有效性,(方法見3.2,優先順序)。圖片的快取策略中,強快取和協商快取同時存在,因為頁面中一般圖片資源較大,但是修改頻率較低,所以使用快取可以提升瀏覽器載入速度。

4.3 雲市場

注釋:

  • Css:強制快取時間為1天;強制快取失效再進行協商快取;
  • Js:強制快取時間為1天;強制快取失效再進行協商快取;
  • Image:強制快取時間為1周;強制快取失效再進行協商快取;

4.4 個人中心

注釋:

  • Css:強制快取時間為1天;強制快取失效再進行協商快取;
  • Js:強制快取時間為1天或1周,不同文件不同;強制快取失效再進行協商快取;
  • Image:強制快取時間為1周;強制快取失效再進行協商快取;

4.5 論壇

注釋:

  • Css:強制快取時間為1周;強制快取失效再進行協商快取;
  • Js:強制快取時間為1周,不同文件不同;強制快取失效再進行協商快取;
  • Image:強制快取時間為1周;強制快取失效再進行協商快取;

4.6 App

移動端快取策略參考其餘部件快取機制,不另做展示。

總結

在現網頁面中,css、js、image等不同類型文件的快取策略大致相同。即同時存在強快取和協商快取策略。對於強快取,給定本地快取的有效時間max-age,一般根據不同文件類型的確定max-age大小;對於協商快取,給定Last-Modified和Etag標識,伺服器端驗證客戶端快取的有效性。本章中給出了,官網各部件瀏覽器端快取策略的簡介。但是,部分文件會存在特殊的快取設置。比如,頁面中很多的js、css、image等會添加版本號,強制刷新快取等。

 

點擊關注,第一時間了解華為雲新鮮技術~