天天看點

徹底了解浏覽器的緩存機制(http緩存機制)

一、概述

浏覽器的緩存機制也就是我們說的HTTP緩存機制,其機制是根據HTTP封包的緩存辨別進行的,是以在分析浏覽器緩存機制之前,我們先使用圖文簡單介紹一下HTTP封包,HTTP封包分為兩種:

同步sau交流學習社群(首發):https://www.mwcxs.top/page/565.html

1、HTTP請求(Request)封包,封包格式為:請求行 – HTTP頭(通用資訊頭,請求頭,實體頭) – 請求封包主體(隻有POST才有封包主體),如下圖

HTTP響應(Response)封包,封包格式為:狀态行 – HTTP頭(通用資訊頭,響應頭,實體頭) – 響應封包主體,如下圖

注:通用資訊頭指的是請求和響應封包都支援的頭域,

分别為Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via;實體頭則是實體資訊的實體頭域,分别為Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header。這裡隻是為了友善了解,将通用資訊頭,響應頭/請求頭,實體頭都歸為了HTTP頭。

二、緩存過程分析

浏覽器與伺服器通信的方式為應答模式,即是:浏覽器發起HTTP請求 – 伺服器響應該請求。那麼浏覽器第一次向伺服器發起該請求後拿到請求結果,會根據響應封包中HTTP頭的緩存辨別,決定是否緩存結果,是則将請求結果和緩存辨別存入浏覽器緩存中,簡單的過程如下圖:

由上圖我們可以知道

1、浏覽器每次發起請求,都會先在浏覽器緩存中查找該請求的結果以及緩存辨別

2、浏覽器每次拿到傳回的請求結果都會将該結果和緩存辨別存入浏覽器緩存中

以上兩點結論就是浏覽器緩存機制的關鍵,他確定了每個請求的緩存存入與讀取,隻要我們再了解浏覽器緩存的使用規則,那麼所有的問題就迎刃而解了,本文也将圍繞着這點進行詳細分析。

為了友善大家了解,這裡我們根據是否需要向伺服器重新發起HTTP請求将緩存過程分為兩個部分,分别是強制緩存和協商緩存 。

2.1強制緩存

強制緩存就是向浏覽器緩存查找該請求結果,并根據該結果的緩存規則來決定是否使用該緩存結果的過程,強制緩存的情況主要有三種(暫不分析協商緩存過程),如下:

(1)不存在該緩存結果和緩存辨別,強制緩存失效,則直接向伺服器發起請求(跟第一次發起請求一緻),如下圖:

(2)存在該緩存結果和緩存辨別,但是結果已經失效,強制緩存失效,則使用協商緩存(暫不分析),如下圖

(3)存在該緩存結果和緩存辨別,且該結果沒有還沒有失效,強制緩存生效,直接傳回該結果,如下圖:

那麼強制緩存的緩存規則是什麼?

答:當浏覽器向伺服器發送請求的時候,伺服器會将緩存規則放入HTTP響應的封包的HTTP頭中和請求結果一起傳回給浏覽器,控制強制緩存的字段分别是Expires和Cache-Control,其中Cache-Conctrol的優先級比Expires高。

2.1.1Expires

Expires是HTTP/1.0控制網頁緩存的字段,其值為伺服器傳回該請求的結果緩存的到期時間,即再次發送請求時,如果用戶端的時間小于Expires的值時,直接使用緩存結果。

Expires是HTTP/1.0的字段,但是現在浏覽器的預設使用的是HTTP/1.1,那麼在HTTP/1.1中網頁緩存還是否由Expires控制?

到了HTTP/1.1,Expires已經被Cache-Control替代,原因在于Expires控制緩存的原理是使用用戶端的時間與服務端傳回的時間做對比,如果用戶端與服務端的時間由于某些原因(時區不同;用戶端和服務端有一方的時間不準确)發生誤差,那麼強制緩存直接失效,那麼強制緩存存在的意義就毫無意義。、

那麼Cache-Control又是如何進行控制的?

2.1.2Cache-Control

在HTTP/1.1中,Cache-Control是最重要的規則,主要用于控制網頁緩存,主要取值為:

(1)public:所有内容都将被緩存(用戶端和代理伺服器都可緩存)

(2)private:所有内容隻有用戶端可以緩存,Cache-Control的預設取值

(3)no-cache:用戶端緩存内容,但是是否使用緩存則需要經過協商緩存來驗證決定

(4)no-store:所有内容都不會被緩存,即不使用強制緩存,也不使用協商緩存

(5)max-age=xxx (xxx is numeric):緩存内容将在xxx秒後失效

接下來,我們直接看一個例子,如下:

由上面的例子我們可以知道:

(1)HTTP響應封包中expires的時間值,是一個絕對值

(2)HTTP響應封包中Cache-Control為max-age=600,是相對值

由于Cache-Control的優先級比expires,那麼直接根據Cache-Control的值進行緩存,意思就是說在600秒内再次發起該請求,則會直接使用緩存結果,強制緩存生效。

注:在無法确定用戶端的時間是否與服務端的時間同步的情況下,Cache-Control相比于expires是更好的選擇,是以同時存在時,隻有Cache-Control生效。

了解強制緩存的過程後,我們拓展性的思考一下:

浏覽器的緩存存放在哪裡,如何在浏覽器中判斷強制緩存是否生效?

這裡我們以部落格的請求為例,狀态碼為灰色的請求則代表使用了強制緩存,請求對應的Size值則代表該緩存存放的位置,分别為from memory cache 和 from disk cache。

那麼from memory cache 和 from disk cache又分别代表的是什麼呢?什麼時候會使用from disk cache,什麼時候會使用from memory cache呢?

from memory cache代表使用記憶體中的緩存,from disk cache則代表使用的是硬碟中的緩存,浏覽器讀取緩存的順序為memory –> disk。

雖然我已經直接把結論說出來了,但是相信有不少人對此不能了解,那麼接下來我們一起詳細分析一下緩存讀取問題,這裡仍讓以我的部落格為例進行分析:

通路https://heyingye.github.io/ –> 200 –> 關閉部落格的标簽頁 –> 重新打開https://heyingye.github.io/ –> 200(from disk cache) –> 重新整理 –> 200(from memory cache)

過程如下:

(1)通路部落格網站

(2)關閉部落格的标簽頁

(3)重新打開部落格

(4)重新整理

看到這裡可能有人小夥伴問了,最後一個步驟重新整理的時候,不是同時存在着from disk cache和from memory cache嗎?

對于這個問題,我們需要了解記憶體緩存(from memory cache)和硬碟緩存(from disk cache),如下:

(1)記憶體緩存(from memory cache):記憶體緩存具有兩個特點,分别是快速讀取和時效性:

1、快速讀取:記憶體緩存會将編譯解析後的檔案,直接存入該程序的記憶體中,占據該程序一定的記憶體資源,以友善下次運作使用時的快速讀取。

2、時效性:一旦該程序關閉,則該程序的記憶體則會清空。

(2)硬碟緩存(from disk cache):硬碟緩存則是直接将緩存寫入硬碟檔案中,讀取緩存需要對該緩存存放的硬碟檔案進行I/O操作,然後重新解析該緩存内容,讀取複雜,速度比記憶體緩存慢。

在浏覽器中,浏覽器會在js和圖檔等檔案解析執行後直接存入記憶體緩存中,那麼當重新整理頁面時隻需直接從記憶體緩存中讀取(from memory cache);而css檔案則會存入硬碟檔案中,是以每次渲染頁面都需要從硬碟讀取緩存(from disk cache)。

2.2協商緩存

協商緩存就是強制緩存失效後,浏覽器攜帶緩存辨別向伺服器發起請求,由伺服器根據緩存辨別決定是否使用緩存的過程,主要有以下兩種情況:

(1)協商緩存生效,傳回304,如下

(2)協商緩存失敗,傳回200和請求結果,如下

同樣,協商緩存的辨別也是在響應封包的HTTP頭中和請求結果一起傳回給浏覽器的,控制協商緩存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的優先級比Last-Modified / If-Modified-Since高。

2.2.1Last-Modified / If-Modified-Since

(1)Last-Modified是伺服器響應請求時,傳回該資源檔案在伺服器最後被修改的時間,如下:

(2)If-Modified-Since則是用戶端再次發起該請求時,攜帶上次請求傳回的Last-Modified值,通過此字段值告訴伺服器該資源上次請求傳回的最後被修改時間。伺服器收到該請求,發現請求頭含有If-Modified-Since字段,則會根據If-Modified-Since的字段值與該資源在伺服器的最後被修改時間做對比,若伺服器的資源最後被修改時間大于If-Modified-Since的字段值,則重新傳回資源,狀态碼為200;否則則傳回304,代表資源無更新,可繼續使用緩存檔案,如下。

2.2.2Etag / If-None-Match

(1)Etag是伺服器響應請求時,傳回目前資源檔案的一個唯一辨別(由伺服器生成),如下:

(2)If-None-Match是用戶端再次發起該請求時,攜帶上次請求傳回的唯一辨別Etag值,通過此字段值告訴伺服器該資源上次請求傳回的唯一辨別值。伺服器收到該請求後,發現該請求頭中含有If-None-Match,則會根據If-None-Match的字段值與該資源在伺服器的Etag值做對比,一緻則傳回304,代表資源無更新,繼續使用緩存檔案;不一緻則重新傳回資源檔案,狀态碼為200,如下。

注:Etag / If-None-Match優先級高于Last-Modified / If-Modified-Since,同時存在則隻有Etag / If-None-Match生效。

三、總結

強制緩存優先于協商緩存進行,若強制緩存(Expires和Cache-Control)生效則直接使用緩存,若不生效則進行協商緩存(Last-Modified / If-Modified-Since和Etag / If-None-Match),協商緩存由伺服器決定是否使用緩存,若協商緩存失效,那麼代表該請求的緩存失效,重新擷取請求結果,再存入浏覽器緩存中;生效則傳回304,繼續使用緩存,主要過程如下:

以上便是浏覽器緩存的過程

文中有錯誤的地方希望指出,共同進步

繼續閱讀