瀏覽器的緩存機制-徹底理解強緩存與協商緩存看這篇就夠了


瀏覽器緩存

1. 前言

瀏覽器緩存 是瀏覽器將用戶請求過的靜態資源(html、css、js),存儲到電腦本地磁盤中,當瀏覽器再次訪問時,就可以直接從本地加載了,不需要再去服務端請求了。

但也不是說緩存沒有缺點,如果處理不當,可能會導致服務端代碼更新了,但是用戶卻還是老頁面。所以前端們要針對項目中各個資源的實際情況,做出合理的緩存策略。

緩存的優點:

  • 減少了冗余的數據傳輸,節省網費
  • 減少服務器的負擔,提升網站性能
  • 加快了客戶端加載網頁的速度

2. 緩存流程

這里先介紹一下瀏覽器緩存資源的一個大概的流程。

我們可以認為,瀏覽器里有一個專門存放緩存規則的一個數據庫,也可以說是一個映射表,把緩存資源信息,同電腦磁盤中的實際文件的地址,對應起來。(大概意思,別較真)

而這個緩存規則的表,在瀏覽器中是可以看到的: chrome://cache/

不過我升級了瀏覽器之后,就不好使了,但是找到了 chrome://net-internals/#httpCache ,不知道是不是就是原來的,知道的同學也可以反饋一下

瀏覽器第一次請求資源時

上面所說的 緩存規則,就是聲明所請求的這個資源,要采取哪種緩存策略?緩存多長時間?等等。。。而這個規則,是在http的header中的返回來的。

注意: 是response header ,而不是 request header !!!

而實際上, request header 中也會攜帶規則信息,下面會講,要區分 request 和 response

3. 緩存規則

強緩存和協商緩存。

強緩存

簡單粗暴,如果資源沒過期,就取緩存,如果過期了,則請求服務器。

如何判斷資源是否過期呢,也就是說強緩存的規則怎么看?

主要是看 response headers 中的 Cache-Control 的值,圖中的max-age = 31xxxxxxx,就是說在這些秒內,都直接使用緩存,超過了就繼續請求服務器

而和 Cache-Control 並列的,還有一個 Expires ,已經基本淘汰了,所以不用管

Cache-Control 的幾個取值含義:

private: 僅瀏覽器可以緩存

public: 瀏覽器和代理服務器都可以緩存(對於private和public,前端可以認為一樣,不用深究)

max-age=xxx 過期時間(重要)

no-cache 不進行強緩存(重要)

no-store 不強緩存,也不協商緩存,基本不用,緩存越多才越好呢

注意:規則可以同時多個

所以,對於強緩存,我們主要研究 Cache-Control 中的 max-age 和 no-cache

所以,判斷該資源是否命中強緩存,就看 response 中 Cache-Control 的值,如果有max-age=xxx秒,則命中強緩存。如果Cache-Control的值是no-cache,說明沒命中強緩存,走協商緩存。

強緩存流程:

所以強緩存步驟已經很清晰了:

  1. 第一次請求 a.js ,緩存表中沒該信息,直接請求后端服務器。
  2. 后端服務器返回了 a.js ,且 http response header 中 cache-control 為 max-age=xxxx,所以是強緩存規則,存入緩存表中。
  3. 第二次請求 a.js ,緩存表中是 max-age, 那么命中強緩存,然后判斷是否過期,如果沒過期,直接讀緩存的a.js,如果過期了,則執行協商緩存的步驟了。

注意

這里有個問題,就是 max-age = 0 ,和 no-cache 有啥區別,我理解的是,no-cache直接不進行強緩存,讓你去走協商緩存,而max-age=0是進行強緩存,但是過期了,需要更新。。。雖然實際上看起來兩者效果是一樣的。

www.itranslater.com/qa/details/…

協商緩存

觸發條件:

  1. Cache-Control 的值為 no-cache (不強緩存)
  2. 或者 max-age 過期了 (強緩存,但總有過期的時候)

也就是說,不管怎樣,都可能最后要進行協商緩存(no-store除外)

這個圖,雖然強緩存命中,但是也有 ETag 和 Last-Modified ,這兩個就是協商緩存的相關規則。雖然之前的強緩存流程和他倆沒關。。。

ETag:每個文件有一個,改動文件了就變了,可以看似md5

Last-Modified:文件的修改時間

也就是說,每次http返回來 response header 中的 ETag和 Last-Modified,在下次請求時在 request header 就把這兩個帶上(但是名字變了ETag-->If-None-Match,Last-Modified-->If-Modified-Since ),服務端把你帶過來的標識,資源目前的標識,進行對比,然后判斷資源是否更改了。

這個過程是循環往復的,即緩存表在每次請求成功后都會更新規則。

1. 第n次請求成功時:

2. 緩存表中更新該資源的 ETag 值

3. 第n+1次請求:

從緩存表中取該資源最新的ETag,然后加在 request header 中, 注意變名字了,由 ETag -- > If-None-Match

圖:

所以協商緩存步驟總結:

  1. 請求資源時,把用戶本地該資源的 ETag 同時帶到服務端,服務端和最新資源做對比。
  2. 如果資源沒更改,返回304,瀏覽器讀取本地緩存。
  3. 如果資源有更改,返回200,返回最新的資源。

4. 緩存命中顯示

  1. 從服務器獲取新的資源

  1. 命中強緩存,且資源沒過期,直接讀取本地緩存

  1. 命中協商緩存,且資源未更改,讀取本地緩存

注意:協商緩存無論如果,都要向服務端發請求的,只不過,資源未更改時,返回的只是header信息,所以size很小;而資源有更改時,還要返回body數據,所以size會大。

7. 其他

0. 怎么配置資源的緩存規則

可以有后端服務器配置,也可以在nginx中配置,稍后會更新一張nginx的配置

1. 為什么要有Etag

你可能會覺得使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,為什么還需要Etag呢?HTTP1.1中Etag的出現(也就是說,ETag是新增的,為了解決之前只有If-Modified的缺點)主要是為了解決幾個Last-Modified比較難解決的問題:

  • 一些文件也許會周期性的更改,但是他的內容並不改變(僅僅改變的修改時間),這個時候我們並不希望客戶端認為這個文件被修改了,而重新GET;

  • 某些文件修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒);

  • 某些服務器不能精確的得到文件的最后修改時間。

2. 強緩存與協商緩存的區別可以用下表來表示:

3. 用戶行為對緩存的影響

即:F5 會 跳過強緩存規則,直接走協商緩存;;;Ctrl+F5 ,跳過所有緩存規則,和第一次請求一樣,重新獲取資源

4. 項目緩存策略

比如 vue 項目,腳手架已經將更改的文件做 hash 處理了,因此一般的 js、css 文件不需要我們再去操作。

而對於 index.html,我們需要在 nginx 上做 no-store 處理,即完全不緩存 index.html,每次都請求最新的html。。。因為 html 中會外鏈 css、js,如果我 html 還是走的緩存,那鏈接的還是老的 css 啊,想想???

6. 總結

借兩個圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM