淺析瀏覽器快取

william_li發表於2019-08-10

前言

瀏覽器快取對開發者來說一直都是一個有愛又恨的存在,一方面幫助開發者提升使用者體驗,另一方面有時會抽風,讀取快取展示錯誤的內容,因此,希望對瀏覽器快取做一個總結,避免開發時因為快取機制而過多耗費時間。接下來,就進入瀏覽器快取的世界

什麼是快取

快取是指一個資源存在於伺服器和客戶端之間的副本,快取會根據請求儲存輸出內容的副本,當下一個請求進來的時候,如果是相同的URL,快取會根據快取機制決定是直接使用副本響應還是向源伺服器重新請求,當你訪問一個網站時,開啟除錯皮膚,你會發現幾乎靜態資源請求都是從快取中讀取出來的,如圖:

淺析瀏覽器快取

為什麼要快取

不用快取可以嗎?當然可以,至於後果是什麼?試了就知道。用了快取之後,會有什麼好處:

  • 減少網路頻寬消耗。無論對於網站運營方還是使用者,頻寬都是和錢掛鉤的,當使用快取時,產生的網路流量是極小的,對於兩邊都可以降低開銷
  • 降低伺服器壓力。當使用快取時,可以有效減少使用者對源伺服器的請求,從而降低伺服器壓力
  • 加快網頁開啟速度,提升使用者體驗。請求快取比請求源伺服器所話費的時間要短的多,因此內容可以更快的觸達使用者,以提升體驗

瀏覽器快取

前菜結束上硬菜,本篇主角瀏覽器快取,瀏覽器快取是眾多web快取分類中的一種,主要分為:

  • Memory Cache
  • Service Worker Cache
  • HTTP Cache
  • Push Cache

Memory Cache

Memory Cache指的是記憶體中的快取,它有如下幾個特點:

  • 響應速度最快,是瀏覽器請求時最先去嘗試命中的快取
  • 生命週期短,一旦程式被關閉就會被清空
  • 記憶體有限,資源存放位置隨機
  • 不關心資源的HTTP快取頭的Cache-Control值,在同一個程式會被重用

來看一個例子:

淺析瀏覽器快取

淺析瀏覽器快取
第一張圖是第一次開啟網頁時擷取的,圈圈標記的圖片時存放在Disk Cache裡面的,第二張圖時網頁重新整理時擷取的,圈圈標記的圖片是存放在Memory Cache中的,同樣的圖片兩次為什麼是從不同的快取中讀取的呢?因為Memory Cache程式關閉時就會清空,但是第二次重新整理的時候,第一次瀏覽器解析圖片檔案進入Memory Cache,第二次重新整理時由於Memory Cache是瀏覽器請求時最先去嘗試命中的快取,因此會直接去從Memory Cache中取

Service Worker Cache

Service Worker是一種獨立於主執行緒之外的JavaScript執行緒,不會對當前程式的執行執行緒造成堵塞,通過Service Worker我們可以自由控制快取哪些檔案、如何匹配快取、如何讀取快取,通過Service Worker實現的快取稱為Service Worker Cache,如果你對Service Worker有更深入瞭解的興趣,可以去看看我之前的一篇部落格:傳送門

HTTP Cache

HTTP Cache是我們日常開發中接觸最多也是最為熟悉的快取,HTTP Cache通常可以分為強快取和協商快取,快取策略都是通過HTTP Header來實現的,強快取的優先順序高於協商快取,在命中強快取失敗的情況下才會去命中協商快取

強快取

強快取主要通過設定HTTP Header Expires和Cache-Control兩個欄位控制,當請求發出時。瀏覽器會根據上一次請求時記錄的Expires和Cache-Control來判斷是否命中強快取,若命中則直接從強快取中取資源,不會再向服務傳送請求,當命中強快取時,HTTP狀態碼返回200,且Size顯示from disk cache,如圖所示:

淺析瀏覽器快取

Expires

Expires快取過期時間,值為一個時間戳。如圖:

淺析瀏覽器快取
當我們兩次向同一個伺服器請求資源時,第二次請求時,瀏覽器會先對比Expires時間戳和本地時間,如果本地時間小於Expires時間戳就會去快取中取資源,但是這樣存在一個問題,Expires依賴客戶端時間,如果客戶端時間和服務端時間不一致時,就會產生問題,Expires是HTTP1.0標準下的欄位,考慮到這個問題,因此在HTTP1.1標準下新增了Cache-Control欄位

Cache-Control

Cache-Control欄位是Expires欄位的完全替代方案,它做Expires欄位能做的所有事,還有Expires欄位不能做的事情,當前還在用Expires欄位的目的只是向下相容,Cache-Control欄位包含多個指令,這裡介紹幾個最常用的:

  • max-age:max-age指令控制資源的有效期,值為時間長度,如圖:
    淺析瀏覽器快取
    當客戶端傳送的請求中包含max-age指令時,瀏覽器會向伺服器確認快取的有效性,如果判定快取資源的快取時間數值比指定的時間數值小,那麼客戶端就接收快取資源,當指定max-age值為0時,通常會向伺服器傳送請求
    當伺服器返回的響應中包含max-age指令時,表示這段時間內,響應由快取控制,瀏覽器不會再向伺服器確認資源的有效性,而是直接返回快取
  • s-maxage:s-maxage指令的功能和max-age指令的相同,不同點是s-maxage指令只適用於供多位使用者使用的公共快取伺服器(代理伺服器),s-maxage的優先順序高於maxage,當s-maxage未過期時,會向公共快取伺服器請求快取
  • public指令與private指令:當使用public指令時,則表示此快取是公有快取,可以被其他使用者使用,當使用private指令時,表示該快取時私有快取,只有在特定使用者請求時才會返回快取
  • no-cache:防止從快取中返回過期資源,當客戶端請求中包含no-cache指令,表示客戶端將不會接收快取過的響應,快取伺服器必須把客戶端請求轉發給源伺服器,當伺服器返回的響應中包含no-cache指令,快取伺服器不能對資源進行快取,儲存在本地快取區中快取在與源伺服器進行新鮮度再驗證之前,快取不能將其提供給客戶端使用
  • no-store:不使用任何快取,直接向源伺服器請求下載內容

協商快取

協商快取就是強制快取失效後,瀏覽器瀏覽器攜帶快取標識向服務發起請求,由伺服器更具快取標識決定是否返回快取,主要有兩種情況:

  • 如果服務端提示資源未改動,資源會被重定向到瀏覽器快取,這種情況下對應的網路狀態碼為304,如圖:

淺析瀏覽器快取

  • 協商快取失敗,資源更新了,重新返回請求結果,這種情況下對應的網路狀態碼為200

接下來介紹和協商快取相關的頭部欄位:

Last-Modified/If-Modified-since

Last-Modified指明資源最終修改的時間,值為一個時間戳,如圖:

淺析瀏覽器快取
當快取要對已快取的文件進行再驗證時,請求頭中就會包含一個If-Modified-since首部,其攜帶有此資源最後修改的時間戳,如圖:

淺析瀏覽器快取
如果在此期間內容被修改,最後的修改日期就會有所不同,源伺服器就會返回新的內容重新響應,否則就會返回304,重定向到瀏覽器快取。
使用Last-Modified存在兩個弊端:

  • 我們開啟了檔案,但是並沒有修改檔案內容,伺服器還是會認為我們修改了這個檔案,Last-Modified會被更新,下次請求時會重新響應
  • If-Modified-since只能感應以秒為最小單位的時間差,當改動檔案速度過快,小於1s時,無法感知檔案變化,導致應該重新請求時,拉到快取資源

由於這些缺陷HTTP1.1出現了Etag/If-None-Match

Etag/If-None-Match

ETag能告知客戶端實體標識,它是一種可將資源以字串形式做唯一標識的方式。伺服器會為每份資源分配對應的ETag值,當資源更新ETag值也會更新,如圖:

淺析瀏覽器快取
當我們下次請求時,請求頭裡會帶上一個If-None-Match字串提供服務端對比,如圖:

淺析瀏覽器快取
如果伺服器上的標籤已經發生了變化,伺服器會在一個200響應中返回新的內容以及新的ETag,否則返回304重定向到快取

HTTP快取決策

淺析瀏覽器快取
此圖源自google,清楚展示了HTTP Cache決策的過程,對上面介紹的快取過程做了一個完美的總結

Push Cache

Push Cache指HTTP2在server push階段存在的快取,是HTTP2 session的一部分,不是一個持久化的快取,當session結束時,快取也會隨之結束,不同的頁面只要共享了同一個HTTP2連線,那麼它們就可以共享同一個Push Cache,如果你對Push Cache還有更多的興趣,這裡提供三篇文章供你閱讀:

總結

此篇文章記錄總結了瀏覽器快取相關的一些知識點,是個人最近對快取知識的一個總結,希望對大家也能有所幫助。
如果有錯誤或不嚴謹的地方,歡迎批評指正,如果喜歡,歡迎點贊

相關文章