談談我對前端緩存的理解

本文主要講解了前端緩存中的強緩存和協商緩存,與緩存相關的首部字段,緩存的不同位置及其之間的區別等。

爲什麼要使用緩存

使用緩存有如下優點:

  • 減少冗餘的數據傳輸
  • 節省網絡費用,緩解網絡瓶頸問題
  • 降低對原始服務器的要求,服務器可以更快響應,避免出現過載
  • 降低距離時延

瀏覽器請求資源的過程

瀏覽器第一次請求資源:

  • 本地無緩存數據
  • 向服務器發送請求
  • 從服務器獲取資源,並協商緩存(是否緩存,獲取資源的Expires、Cache-Control、Etag、Last-Modified等信息)
  • 最後呈現頁面。

瀏覽器進行再次請求:

  • 先獲取該資源緩存的header信息,判斷是否命中緩存(根據cache-control和expires信息判斷),若命中直接從緩存中獲取資源信息,包括緩存header信息。本次請求不會與服務器進行通信。—— 強緩存
  • 如果沒有命中強緩存,瀏覽器會發送請求到服務器,請求會攜帶第一次請求返回的有關緩存的header字段信息(Last-Modified/If-Modified-Since和Etag/If-None-Match),由服務器根據請求中的相關header信息來比對結果是否緩存命中;若命中,則服務器返回新的響應header信息更新緩存中的對應header信息,但是並不返回資源內容,它會告知瀏覽器可以直接從緩存獲取;否則返回最新的資源內容。—— 協商緩存

以上可以看出強緩存與協商緩存的特點:

  • 強緩存:直接使用本地的緩存,不用跟服務器進行通信
  • 協商緩存:將資源一些相關信息返回給服務器,讓服務器判斷瀏覽器是否能直接使用本地緩存,整個過程至少與服務器通信一次

與強緩存相關的header字段(包含在響應報文中,服務器發來的)

與強緩存主要相關的首部字段有expires和cache-control:max-age=number。並且如果cache-control與expires同時存在的話,cache-control的優先級高於expires。下面對這兩者進行詳細的介紹:

  • expires,這是http1.0時的規範;它的值爲一個絕對時間的GMT格式的時間字符串,如Mon, 10 Jun 2015 21:31:12 GMT,如果發送請求的時間在expires之前,那麼本地緩存始終有效,否則就會發送請求到服務器來獲取資源
  • cache-control:max-age=number,這是http1.1時出現的header信息,主要是利用該字段的max-age值來進行判斷,它是一個相對值;資源第一次的請求時間和Cache-Control設定的有效期,計算出一個資源過期時間,再拿這個過期時間跟當前的請求時間比較,如果請求時間在過期時間之前,就能命中緩存,否則就不行;cache-control除了該字段外,還有下面幾個比較常用的設置值:
    1)no-cache:不使用本地緩存。需要使用緩存協商,先與服務器確認返回的響應是否被更改,如果之前的響應中存在ETag,那麼請求的時候會與服務端驗證,如果資源未被更改,則可以避免重新下載。
    2)no-store:直接禁止遊覽器緩存數據,每次用戶請求該資源,都會向服務器發送一個請求,每次都會下載完整的資源。
    3)public:可以被所有的用戶緩存,包括終端用戶和CDN等中間代理服務器。
    4)private:只能被終端用戶的瀏覽器緩存,不允許CDN等中繼緩存服務器對其緩存。

協商緩存相關的header字段(響應報文中/請求報文中)

協商緩存都是由服務器來確定緩存資源是否可用的,所以客戶端與服務器端要通過某種標識來進行通信,從而讓服務器判斷請求資源是否可以緩存訪問,這主要涉及到下面兩組header字段,這兩組搭檔都是成對出現的,即第一次請求的響應頭帶上某個字段(Last-Modified或者Etag),則後續請求則會帶上對應的請求字段(If-Modified-Since或者If-None-Match),若響應頭沒有Last-Modified或者Etag字段,則請求頭也不會有對應的字段。

  • Last-Modified/If-Modified-Since
    二者的值都是GMT格式的時間字符串,具體過程:
    (1)瀏覽器第一次跟服務器請求一個資源,服務器在返回這個資源的同時,在respone的header加上Last-Modified的header,這個header表示這個資源在服務器上的最後修改時間;
    (2)瀏覽器再次跟服務器請求這個資源時,在request的header上加上If-Modified-Since的header,這個header的值就是上一次請求時返回的Last-Modified的值;
    (3)服務器再次收到資源請求時,根據瀏覽器傳過來If-Modified-Since和資源在服務器上的最後修改時間判斷資源是否有變化,如果沒有變化則返回304 Not Modified,但是不會返回資源內容;如果有變化,就正常返回資源內容。當服務器返回304 Not Modified的響應時,response header中不會再添加Last-Modified的header,因爲既然資源沒有變化,那麼Last-Modified也就不會改變,這是服務器返回304時的response header;
    (4)瀏覽器收到304的響應後,就會從緩存中加載資源;
    (5)如果協商緩存沒有命中,瀏覽器直接從服務器加載資源時,Last-Modified的Header在重新加載的時候會被更新,下次請求時,If-Modified-Since會啓用上次返回的Last-Modified值。
  • Etag/If-None-Match
    這兩個值是由服務器生成的每個資源的唯一標識字符串,當資源有變化時,這個值就會改變;其判斷過程與Last-Modified/If-Modified-Since類似,與Last-Modified不一樣的是,當服務器返回304 Not Modified的響應時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag跟之前的沒有變化。
既生Last-Modified何生Etag

你可能會覺得使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,爲什麼還需要Etag呢?HTTP1.1中Etag的出現主要是爲了解決幾個Last-Modified比較難解決的問題:

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

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

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

這時,利用Etag能夠更加準確的控制緩存,因爲Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符。

Last-Modified與ETag是可以一起使用的,服務器會優先驗證ETag,一致的情況下,纔會繼續比對Last-Modified,最後才決定是否返回304。

緩存位置

緩存的位置大致分爲以下三類: Service WorkerMemory CacheDisk Cache 。 並且它們的優先級就是按照這個順序,從前往後尋找,找到即返回;找不到則繼續。若最後資源在這些地方都沒有找到的話,再去服務器請求資源。

service worker

用戶自定義緩存哪些資源到硬盤上,什麼情況下使用緩存(路由匹配規則),緩存匹配並返回。

清空緩存的情況分兩種,一是手動調用api,二是容量超過限制,被瀏覽器全部情況。

這種方式緩存的資源查看方式:開發者工具 -> Application -> Cache Storage。

當資源請求被髮起的時候,瀏覽器首先從service worker中查找資源,如果緩存爲命中,一般情況會使用fetch()方法繼續獲取資源,這時瀏覽器就去memory cache 或disk cache中進行下一次找緩存的工作。

特別注意:經過fetch()方法獲取的資源,都會顯示 from ServiceWorker,不管資源實際情況是從memory cache 或disk cache,還是從網絡重新請求獲取的。

memory cache

內存中的緩存,幾乎所有的網絡請求資源都會被瀏覽器自動加入到memory cache中,被短期存儲,關閉瀏覽器窗口,memory cache就失效了。

從memory cache中獲取緩存內容的時候,瀏覽器會忽視例如max-age=0,no-cache等頭部配置。

但如果頭部配置設置了no-store,那麼資源就不會進入memory-cache。

disk cache

硬盤上的緩存,持久存儲,允許相同資源跨回話跨站點的使用。

嚴格根據HTTP頭部字段判定該緩存哪些資源,哪些資源可用,以及哪些資源過期了需要重新請求。

當請求命中緩存時,就從硬盤中讀取資源。絕大多數的緩存都來自disk cache。

如何判斷資源是從哪來的

Chrome開發工具 -> network -> 查看size那一列的值

(1)多少多少k:網絡請求

(2)form memory cache

(3) disk cache

(4)from ServiceWorker

瀏覽器的行爲

所謂瀏覽器的行爲,指的就是用戶在瀏覽器如何操作時,會觸發怎樣的緩存策略。主要有 3 種:

  • 打開網頁,地址欄輸入地址: 查找 disk cache 中是否有匹配。如有則使用;如沒有則發送網絡請求。
  • 普通刷新 (F5):因爲 TAB 並沒有關閉,因此 memory cache 是可用的,會被優先使用(如果匹配的話)。其次纔是 disk cache。
  • 強制刷新 (Ctrl + F5):瀏覽器不使用緩存,因此發送的請求頭部均帶有 Cache-control: no-cache(爲了兼容,還帶了 Pragma: no-cache)。服務器直接返回 200 和最新內容。

參考文章:
http協商緩存VS強緩存
一文讀懂前端緩存

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