瀏覽器靜態資源緩存機制

先看上圖,如果對圖中的(a)(b)(c)(d)四個過程的處理方式都很清楚了,那麼請不用再看本文了。

兩個概念

·      強緩存
用戶發送的請求,直接從客戶端緩存中獲取,不發送請求到服務器,不與服務器發生交互行爲。

·      協商緩存
用戶發送的請求,發送到服務器後,由服務器判定是否從緩存中獲取資源。

·      兩者共同點:客戶端獲得的數據最後都是從客戶端緩存中獲得。

·      兩者的區別:從名字就可以看出,強緩存不與服務器交互,而協商緩存則需要與服務器交互。

四個過程詳解

a)瀏覽器判定是否有緩存

先理解個概念,所謂客戶端緩存就是指用戶設備中本地資源。不同瀏覽器緩存文件的地址也不盡相同。
我們以chrome爲例來查看下瀏覽器緩存文件的地址,
1
)首先在chrome中輸入:chrome://chrome-urls/,看到一堆列表,裏面隱藏了許多瀏覽器的奧祕,有興趣的可以自己深扒。
2
)找到 chrome://cache(當然也可以直接輸入這個地址)

從上圖中可以看到,第一個從緩存中取的文件是: https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/css/super_min_fec0412a.css

然後回到chrome://cache 頁面,找到它,並點擊進去,可以看到

回到問題,瀏覽器怎麼判定是否有緩存,就可以轉化爲瀏覽器去讀取本地放緩存的地方(注:不同瀏覽器不同系統都會不同)是否有該對應的請求啦。

總結來說就是個查找文件是否存在的問題。

b)緩存是否過期

我們再以這張圖爲例,這張圖中表明,客戶端保留了一個服務器端的responseheader
裏面的Date字段表明此次緩存時服務器的時間。
裏面有兩個字段:expires Cache-Control

·      expires
Http1.0
中的標準,表明過期時間,注意此處的時間都是指的是服務器的時間。
可以看到過期時間被設定爲了:Thu, 28 Sep 2017 06:38:37GMT

存在的問題:服務器時間與客戶端時間的不一致,就會導致緩存跟期待效果出現偏差。

Cache-Control
Http1.1
中的標準,可以看成是 expires 的補充。使用的是相對時間的概念。
簡單介紹下Cache-Control的屬性設置。
1
max-age: 設置緩存的最大的有效時間,單位爲秒(s)。max-age會覆蓋掉Expires
2) s-maxage:
只用於共享緩存,比如CDN緩存(s -> share)。與max-age 的區別是:max-age用於普通緩存,
s-maxage用於代理緩存。如果存在s-maxage,則會覆蓋max-age Expires.
3) public
:響應會被緩存,並且在多用戶間共享。默認是public
4) private:
響應只作爲私有的緩存,不能在用戶間共享。如果要求HTTP認證,響應會自動設置爲private
5
no-cache: 指定不緩存響應,表明資源不進行緩存。但是設置了no-cache之後並不代表瀏覽器不緩存,而是在緩存前要向服務器確認資源是否被更改。因此有的時候只設置no-cache防止緩存還是不夠保險,還可以加上private指令,將過期時間設爲過去的時間。
6
no-store: 絕對禁止緩存。
7
must-revalidate: 如果頁面過期,則去服務器進行獲取。
設置cache-control 的規則可以參見下圖:

所以判斷緩存是否過期步驟是:
1
查看是否有cache-control max-age / s-maxage , 如果有,則用服務器時間date + max-age/s-maxage 的秒數計算出新的過期時間,將當前時間與過期時間進行比較,判斷是否過期
2
)查看是否有cache-control max-age / s-maxage,則用expires 作爲過期時間比較

總結:(b)過程執行完後,如果判定爲未過期,則使用客戶端緩存。那麼就是屬於強緩存

c)跟服務器協商是否使用緩存

到這一步的時候,瀏覽器會向服務器發送請求,同時如果上一次的緩存中有Last-modified Etag 字段,
瀏覽器將在request header 中加入If-Modified-Since(對應於Last-modified),If-None-Match(對應於Etag)。

·        Last-modified: 表明請求的資源上次的修改時間。

·        If-Modified-Since:客戶端保留的資源上次的修改時間。

·        Etag:資源的內容標識。(不唯一,通常爲文件的md5或者一段hash值,只要保證寫入和驗證時的方法一致即可)

·      If-None-Match客戶端保留的資源內容標識。

1分佈式系統儘量關閉Etag,因爲每臺機器生成的Etag都不一樣。
2
)分佈式系統裏多臺機器間文件的Last-Modified必須一致,以免負載均衡不同導致對比失敗。

通常情況下,如果同時發送If-None-Match If-Modified-Since字段,服務器只要比較etag 的內容即可,當然具體處理方式,看服務器的約定規則。

d)協商緩存

在這個階段,服務器一般會將Cache-controlexpires last-modifieddateetag 等字段在response header 中返回,便於下次緩存。當然具體的場景,也是看服務器的約定規則設定。

緩存的不同來源

這個問題暫時沒有找到非常滿意的、清楚的回答。

from disk cache

從磁盤中獲取緩存資源,等待下次訪問時不需要重新下載資源,而直接從磁盤中獲取。它的直接操作對象爲CurlCacheManager

from memory cache

從內存中獲取資源,等待下次訪問時不需要重新下載資源,而直接從內存中獲取。Webkit早已支持memoryCache
目前Webkit資源分成兩類,一類是主資源,比如HTML頁面,或者下載項,一類是派生資源,比如HTML頁面中內嵌的圖片或者腳本鏈接,分別對應代碼中兩個類:    MainResourceLoaderSubresourceLoader。雖然Webkit支持memoryCache,但是也只是針對派生資源,它對應的類爲CachedResource,用於保存原始數據(比如CSSJS等),以及解碼過的圖片數據。

區別

當退出進程時,內存中的數據會被清空,而磁盤的數據不會,所以,當下次再進入該進程時,該進程仍可以從diskCache中獲得數據,而memoryCache則不行。

相似

diskCachememoryCache相似之處就是也只能存儲一些派生類資源文件。它的存儲形式爲一個index.dat文件,記錄存儲數據的url,然後再分別存儲該urlresponse信息和content內容。Response信息最大作用就是用於判斷服務器上該urlcontent內容是否被修改。

用戶行爲

最後附上一張,用戶行爲影響瀏覽器的緩存行爲。


Web靜態資源緩存及優化

對於頁面中靜態資源(html/js/css/img/webfont),理想中的效果:

1. 頁面以最快的速度獲取到所有必須靜態資源,渲染飛快;

2. 服務器上靜態資源未更新時再次訪問不請求服務器;

3. 服務器上靜態資源更新時請求服務器最新資源,加載又飛快。

總結下來也就是2個指標:

·        靜態資源加載速度

·        頁面渲染速度

靜態資源加載速度引出了我們今天的主題,因爲最直接的方式就是將靜態資源進行緩存。頁面渲染速度建立在資源加載速度之上,但不同資源類型的加載順序和時機也會對其產生影響,所以也留給了我們更多的優化空間。

當然除了速度,緩存還有另外2大功效,減少用戶請求的帶寬和減少服務器壓力。

先用一張圖來概括下本文中將會涉及到的內容。

常見緩存類型

1、瀏覽器緩存

對於前端而言,這可能是我們最容易忽略的緩存類型,原因在於大部分設置都在服務器運維層面上進行,不屬於前端開發的維護範圍。但靜態資源的內容更新時機其實前端是最清楚的,如果能在理解瀏覽器緩存策略的基礎上合理配置效果最佳。

瀏覽器緩存策略一般通過資源的Response Header來定義,html文件在很早之前的規範裏也可以通過Meta標籤的http-equiv來定義。

一個Response Header示例:

可在w3的官方文檔中查看所有HTTP Response Header字段的定義,跟緩存相關的主要有上圖中被圈出來的幾個:

·        Cache-Control:

o    public:響應被緩存,並且在多用戶間共享。

o    private:默認值,響應只能夠作爲私有的緩存(e.g., 在一個瀏覽器中),不能再用戶間共享;

o    no-cache:響應不會被緩存,而是實時向服務器端請求資源。

o    max-age:數值,單位是秒,從請求時間開始到過期時間之間的秒數。基於請求時間(Date字段)的相對時間間隔,而不是絕對過期時間;

注:HTTP/1.0沒有實現 Cache-Control,所以爲了兼容HTTP/1.0出現了Pragma字段。

·        Pragma: 只有一個用法Pragma: no-cache,它和Cache-Control:no-cache作用一模一樣。(Cache-Control: no-cache是http 1.1才提供的,因此Pragma: no-cache可以使no-cache應用到http 1.0 和http 1.1。)

o    Expires:指定了在瀏覽器上緩衝存儲的頁距過期還有多少時間,等同Cache-control中的max-age的效果,如果同時存在,則被Cache-Control的max-age覆蓋。若把其值設置爲0,則表示頁面立即過期。並且若此屬性在頁面當中被設置了多次,則取其最小值。

注:這個規則允許源服務器,對於一個給定響應,向 HTTP/1.1(或之後)緩存比 HTTP/1.0 提供一個更長的過期時間。

·        Date:生成消息的具體時間和日期;

·        Last-Modified/If-Modified-Since:本地文件在服務器上的最後一次修改時間。緩存過期時把瀏覽器端緩存頁面的最後修改時間發送到服務器去,服務器會把這個時間與服務器上實際文件的最後修改時間進行對比,如果時間一致,那麼返回304,客戶端就直接使用本地緩存文件。

·        Etag/If-None-Match:(EntityTags)是URL的tag,用來標示URL對象是否改變,一般爲資源實體的哈希值。和Last-Modified類似,如果服務器驗證資源的ETag沒有改變(該資源沒有更新),將返回一個304狀態告訴客戶端使用本地緩存文件。Etag的優先級高於Last-Modified,Etag主要爲了解決 Last-Modified無法解決的一些問題。

o    文件也許會週期性的更改,但是他的內容並不改變,不希望客戶端重新get;

o    If-Modified-Since能檢查到的粒度是s級;

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

緩存策略執行過程

本地緩存過期後,瀏覽器會向服務器發送請求,request中會攜帶以下兩個字段:

·        If-Modified-Since:值爲之前response中Last-Modified;

·        If-None-Match:值爲之前response中Etag(如果存在的話);

其中在圖右側的“filemodified?”判斷中,服務器會讀取請求頭這兩個值,判斷出客戶端緩存的資源是否最新,如果是的話服務器就會返回HTTP/304 NotModified響應頭,但沒有響應體。客戶端收到304響應後,就會從緩存中讀取對應的資源;否則返回HTTP/200和響應體。

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