真的只是簡單瞭解下瀏覽器緩存

image.png

01、什麼是HTTP緩存,如何工作的?

當我們打開一個頁面時,會向服務端發起很多次請求,如下圖打開百毒首頁,發起了HTML、各種圖片、JS、CSS等資源共72次請求。這裏面很多資源並不會頻繁變化,每次打開頁面都重新請求下載,就很浪費了。

image.png

瀏覽器緩存也稱爲HTTP緩存,HTTP緩存簡單理解就是本地(瀏覽器)緩存了HTTP響應,以便後續複用,減少向服務端的請求。尤其對於一些靜態資源,如圖片、JS文件、CSS文件等資源,瀏覽器端緩存可以極大提升頁面的加載速度,不用每次都都全部從服務端下載,也減輕了服務端的壓力。

如下圖,再次打開百度首頁,可以看到很多圖片、JS資源、CSS資源都是從緩存加載的,網頁加載飛快。

image.png

📢緩存是一個很重要、很常用的技術,在IT系統中無處不在,基本原理都是就近存儲可能要用的數據,用空間換時間,提升數據的加載效率。

  • 前端瀏覽器緩存HTTP的響應。
  • 後端服務的數據API也會有緩存,避免每次都訪問數據庫,數據庫本身也會有緩存。
  • CDN內容分發也是一種分佈式的緩存。
  • 計算機中的CPU、磁盤也都會有自己的緩存機制。

1.1、基於URL緩存資源

URL是定位資源的唯一路徑,通常來說緩存也是基於URL地址的。但不僅限於URL,也支持以通過Header的字段Accept、Accept-Language 、 Accept-Encoding標記的不同內容進行緩存,可通過Vary字段來申明(/ˈveri/ 改變)。

Vary: Accept-Language

1.2、存在什麼地方?

主要存儲在內存、磁盤上,具體存在哪則由瀏覽器來決定了,比如大文件可能會存在磁盤上,使用很頻繁的資源可能會存儲在內存中,或者都會存儲。

image.png

  • 內存 from memory cache:內存讀取速度快,進程結束內存就釋放了。
  • 磁盤 from disk cache:讀取速度稍慢(其實也是很快的),可以長久保存。

1.3、緩存規則

基本的緩存讀取規則都是先從本地瀏覽器緩存查找,如果有且資源沒有過期就用本地的,否則求去服務端請求。具體過程又分爲強緩存、協商緩存:

  • 第一次請求:本地沒有,訪問服務器獲取響應,瀏覽器會緩存響應。
  • 第二/N次請求:本地有緩存,緩存內容有效(沒有過保質期),則響應狀態碼爲200,直接使用本地緩存。—— 這個過程中,直接使用了本地的緩存內容稱爲“強緩存”。
  • 第N次請求:本地有緩存,但緩存內容已過期,則會向服務端發起請求詢問該資源是否有變化,服務端判斷如果資源沒變化,則返回304(資源沒變化,可繼續食用,沒有body內容),瀏覽器使用本地緩存內容(並更新有效期)。如果服務端判斷資源變了,則返回狀態碼200 + 新的資源,瀏覽器收到會更新緩存。—— 這個過程中,瀏覽器詢問了服務端資源是否有效,進行了協商,稱爲“協商緩存”。

image

所以緩存的使用過程就是,先強緩存(本地緩存有效),再協商緩存。

304: Not Modified 資源未修改,客戶端緩存了資源,重定向到本地。


02、強緩存:本地緩存

🔵強緩存:瀏覽器自行決定的緩存處理機制,不需連接服務端。瀏覽器在請求資源時,先在瀏覽器緩存中查找,如果找到,且緩存有效期正常,則強緩存生效,直接從緩存中獲取響應。否則就會使用協商緩存,向服務端發起請求。

所以這裏關鍵就是判斷緩存是否有效,是否在有效期內。關鍵(Header)字段就是:

  • Expires(HTTP/1.0):過期時間。
  • Cache-Control:max-age(HTTP/1.1):緩存有效時長。

📢都是服務端響應時,在Header上標記的值,瀏覽器根據這個字段值來判等資源是否有效。Cache-Control:max-age優先級更高,也更好用。

2.1、Expires過期時間

HTTP/1.0的技術(已過時),在Header中使用,規定緩存的具體有效期(年月日時分秒),在此期限內則緩存有效。

Expires: Tue, 28 Feb 2022 22:22:22 GMT

缺點是:值的解析和計算不方便,而且依賴於本地的時間,容易被篡改。

2.2、Cache-Control:max-age

Cache-Control 是HTTP/1.1中的一個Header字段,用來實現緩存的各種配置。常用指令max-age設置緩存的最大有效時長,用來替換Expires,如果同時存在則max-age優先。

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Cache-Control: max-age=3600		//3600秒,表示一個小時內有效

Cache-Control常用指令:

指令 說明
max-age 緩存最大週期 (單位秒),超過這個時間緩存被認爲過期
no-cache 強制重新驗證,不會直接使用本地緩存,必須每次都詢問服務器,就是後文的協商緩存
no-store 不緩存,禁用緩存
public 都可以緩存的公共資源,客戶端、代理服務器都可以緩存
private 個性化的、私有化內容,每個用戶請求URL相同但的內容不同的資源,只能客戶端緩存,代理服務器不可緩存
must-revalidate 過期後必須重新驗證(revalidate /riˈvælɪˌdet/ 重新驗證)
immutable 長時間緩存(/ɪˈmjuːtəb(ə)l/ 永恆的)
Cache-Control: private
Cache-Control: public, max-age=31536000  //1年有效期
Cache-Control: max-age=31536000, immutable
Cache-Control: max-age=0, must-revalidate  //立即失效,必須重新驗證(協商緩存)

如果沒有設置Cache-Control字段,採用“啓發式緩存“,儘量的最大限度的使用緩存機制。


03、協商緩存:服務端驗證

🔵協商緩存:瀏覽器需要連接服務端,向服務端詢問資源是否過期,服務端判斷沒過期就繼續用本地緩存,否則返回新的資源。

✔️基本過程都是

  • 請求HTTP資源時,先查找緩存,找到了但緩存過期,或緩存設置了no-cache,開始“協商緩存”。
  • 發起一個HTTP請求,向服務端詢問資源是否過期。
  • 服務端收到請求後驗證資源是否變更,若沒變更則返回304(沒有body,所以速度很快),告訴瀏覽器資源沒有修改,可以繼續使用本地緩存。否則返回200+新的資源。

✔️協商緩存的關鍵(Header)字段爲

  • last-modified:資源最後修改時間。
  • ETag:資源的唯一編碼,文件內容變更後更新。

✔️觸發協商緩存的條件

  • Cache-Control:no-cache :強制使用協商緩存。
  • 本地緩存過期,或Cache-Control: max-age=0

3.1、last-modified 最後修改時間

last-modified 最後修改時間,服務端在Header上給出的資源最後修改時間。

  • 第一次請求資源時,服務端會在響應Header中會返回last-modified字段。
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT
Cache-Control: max-age=3600  //緩存有效期1個小時
  • 再次請求該資源時,瀏覽器發現緩存資源已過期(時間已超過1個小時),開始“協商緩存”。
  • 先發起一個(詢問)HTTP請求,Header中加上if-modified-since(/ˈmɑːdɪfaɪd/ /sɪns/),值爲上次的last-modified值。
GET /index.html HTTP/1.1
Host: example.com
Accept: text/html
If-Modified-Since: Tue, 22 Feb 2022 22:00:00 GMT
  • 服務端收到請求,判斷如果資源最後修改時間相同,認爲資源沒有變化,可以繼續使用本地的緩存,則返回304(無body內容)。否則返回200+新的資源,並更新last-modified
  • 瀏覽器收到304響應後,從本地緩存獲取資源,並恢復其正常緩存狀態,更新Last-Modified,生命延遲1小時。
HTTP/1.1 304 Not Modified
Content-Type: text/html
Date: Tue, 22 Feb 2022 23:22:22 GMT
Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT
Cache-Control: max-age=3600
  • 如果瀏覽器收到200響應,同第一次請求資源一樣,更新緩存資源。

image

⛔缺點:如果1s內有多次文件修改,則會判斷出現問題,因此就有了下面的ETag

3.2、ETag 資源唯一標籤

ETag,機制和last-modified類似,ETag是文件內容的一個唯一標識符,文件變更後會更新標識符,可以看做是文件內容的摘要。值是服務端自定義生成的,目的是爲了標記文件內容的版本,可以用版本號、哈希值等。

  • 第一次請求資源時,服務端在響應Header中會返回ETag字段。
  • 協商緩存時發送HTTP請求,瀏覽器在Header中加上If-None-Match,值爲上一次的ETag值。
  • 服務端收到請求,讀取If-None-Match值,判斷如果匹配一致,文件沒更新,則返回304。否則返回200+新的資源,並更新ETag
  • 瀏覽器收到304響應後,從本地緩存獲取資源,並恢復其正常緩存狀態,更新ETag
  • 如果瀏覽器收到200響應,同第一次請求資源一樣,更新緩存資源。
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=0
Connection: keep-alive
Content-Length: 114
Content-Type: text/html
Date: Wed, 19 Apr 2023 09:05:30 GMT
Etag: "639b0692-72"
Expires: Wed, 19 Apr 2023 09:05:30 GMT   //2023年4月19日09:08,今天早上,現在是下午5點多了。
Last-Modified: Thu, 15 Dec 2022 11:35:46 GMT

📢相比較而言,ETag要更科學、更準確一些。文件修改了並不代碼內容一定有變化,還有就是最後修改時間的單位是秒,如果1秒內的多次變化就會判斷失誤。Etag 優先級高於 Last-Modified。


04、總結一下-流程圖

畫圖!

image


05、一些實踐

5.1、緩存應用

  • 不經常變的靜態資源,如JS、CSS、圖片推薦使用強制緩存,Cache-Control: max-age=31536000
  • HTML文檔推薦使用協商緩存,比如SPA的入口頁面可以使用Cache-Control: no-cache強制每次都使用協商緩存。
  • Last-Modified、ETag可同時使用,ETag優先級更高,但Last-Modified還有額外的價值,可用來標識文件的修改時間。
  • 合理定製不同資源文件的緩存機制、緩存週期。
  • 緩存的Header配置都是在服務端,可以通過Nginx配置。

5.2、緩存破壞

緩存破壞:每次內容變化時都更新URL地址,一般就是更新文件名,或文件名附加版本號。大多WEB項目的JS、CSS文件都是這麼幹的,每次編譯的時候都會更新文件名。

# version in filename
bundle.v123.js

# version in query
bundle.js?v=123

# hash in filename
bundle.YsAIAAAA-QG4G6kCMAMBAAAAAAAoK.js

# hash in query
bundle.js?v=YsAIAAAA-QG4G6kCMAMBAAAAAAAoK

5.3、如何清除緩存?

  • 瀏覽器強制(忽略緩存)刷新:Shift + F5Command + Shift + R(Mac)。
  • 清除瀏覽器緩存:設置 > 歷史記錄 > 清除瀏覽數據。
  • 瀏覽器禁用緩存:瀏覽器調試模式下 > 網絡 > 開啓“禁用緩存”。

image.png


參考資料


©️版權申明:版權所有@安木夕,本文內容僅供學習,歡迎指正、交流,轉載請註明出處!原文編輯地址-語雀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章