HTTP 緩存

前提

瀏覽器通過網絡下載各種各樣的資源,例如 HTML、CSS、JavaScript、圖片、視頻、音頻、字體等等,這是瀏覽器工作過程的第一步,也是非常耗時的一步。其實,很多靜態文件,如 HTML 文本、圖片等,這些資源不經常發生變化,完全可以儲存在客戶端( 保存到本地磁盤中 ),以便下次使用。因此,瀏覽器引入了資源緩存機制,也叫 HTTP 緩存機制。

基本概念

HTTP 緩存的基本思想是在客戶端建立一個資源的緩存池( 以下簡稱資源池 ),所有對資源的請求都會優先獲取緩存中的信息,以決定是否需要向服務器提出資源請求。

示意圖:

圖片描述

查詢方式

資源的唯一性是通過 URL 來標記的,因此從資源池中查詢資源的關鍵字就是 URL。如果兩個資源有不同的 URL,但它們的內容完全一樣,也會被認爲是兩個不同的資源。

生命週期

由於磁盤存儲的空間是有限的,因此,資源池會清除那些“最近最少使用”的資源。

強制緩存

在已緩存的資源未失效( 未過期 )的情況下,不會向服務器發送請求,會直接從資源池中讀取資源。

資源未失效示意圖:

圖片描述

資源已失效示意圖:

圖片描述

緩存規則

對於強制緩存而言,響應頭中有兩個字段標明瞭它的緩存規則,一個是 Expires,另一個是 Cache-Control。

Expires

Expires 的值包含具體的日期和時間,是服務器返回的資源到期時間, 即在此時間之前,可以直接從資源池中讀取資源,無需再次請求服務器。

例子:

Expires: Wed, 31 Jul 2019 02:58:24 GMT

Cache-Control

Cache-Control 可以被用於請求和響應頭中,組合使用多種指令來指定緩存機制。下面列舉了比較常用的指令:

  • private:資源只可以被客戶端緩存,Cache-Control 的默認值。
  • public:資源可以被客戶端和代理服務器緩存。
  • max-age=t :客戶端緩存的資源將在 t 秒後失效。
  • no-cache:需要使用對比緩存來驗證資源( 下面會詳細介紹 )。
  • no-store:不緩存任何資源。

private 和 public 的區別在於是否允許中間節點( 即代理服務器 )進行資源緩存,如果 Cache-Control 值設置爲 public:

客戶端 <--> 代理服務器 <--> 服務器

中間的代理服務器可以緩存資源,如果下一次再請求同一資源,代理服務器就可以直接把自己緩存的資源返回給客戶端,而無需再請求服務器。但如果 Cache-Control 值設置爲 private,表明資源只能被當前用戶在客戶端緩存,屬於私有緩存,不能作爲共享緩存( 代理服務器緩存的資源可以共享 )。

例子:

Cache-Control: max-age=31536000

例子中,Cache-Control 僅指定了 max-age,所以默認爲 private,緩存時間爲 31536000 秒( 365天 )。也就是說,在 365 天內再次請求該資源時,都會直接使用資源池中的資源。

Expires 與 Cache-Control 同時出現

Expires 屬於 HTTP/1.0 的產物,而 Cache-Control 屬於 HTTP/1.1 的產物,如果服務器同時設置了 Expires 與 Cache-Control,那麼以更先進的 Cache-Control 爲準。在某些不支持 HTTP/1.1 的環境中,Expires 才能發揮作用,現階段只是一種兼任性的寫法。

強制緩存的弊端

強制緩存的判定標準,主要依據來自於是否超出某個時間或者某個時間段,而不關心服務器端資源是否已經更新,這可能會導致加載的資源早已不是服務器端最新的內容。

對比緩存( 協商緩存 )

針對強制緩存的弊端,對比緩存需要進行資源比對來判斷是否可以使用緩存。

客戶端第一次請求資源時,服務器會將緩存標識與資源一起返回給客戶端,客戶端將二者備份至資源池中。當再次請求相同資源時( 此時,強制緩存期限已到,緩存資源還在 ),客戶端將備份的緩存標識發送給服務器,服務器根據緩存標識進行驗證,如果驗證結果爲未更新,服務器會返回 304 狀態碼,通知客戶端可以繼續使用緩存資源。

有一點需要特別注意:對比緩存的優先級低於強制緩存,因此只有在強制緩存失效後,客戶端纔會攜帶緩存標識向服務器發起請求。

資源未更新示意圖:

圖片描述

資源已更新示意圖:

圖片描述

緩存規則

不同於強制緩存,對比緩存最重要的是緩存標識的傳遞。緩存標識在請求頭和響應頭之間進行傳遞,具體方式可以分爲以下兩組:

Last-Modified / If-Modified-Since

當我們第一次發出請求時,Last-Modified 由服務器返回,通知客戶端,該資源的最後修改時間。當我們再次請求該資源時,If-Modified-Since 由客戶端發送,其保存了 Last-Modified 的值。服務器收到請求後,將 If-Modified-Since 的值與被請求資源的最後修改時間進行比對。若資源的最後修改時間大於 If-Modified-Since 的值,說明資源被修改過,則返回狀態碼 200 以及最新資源;若資源的最後修改時間小於或等於 If-Modified-Since 的值,說明資源無修改,則返回狀態碼 304,通知客戶端繼續使用緩存資源。

例子:

//第二次發出請求時,請求頭內容
If-Modified-Since: Mon, 23 Jul 2018 08:29:29 GMT

//第二次發出請求時,響應頭內容
Last-Modified: Mon, 23 Jul 2018 08:29:29 GMT

//此時,狀態碼應該爲:
Status Code: 304 Not Modified

ETag / If-None-Match

當我們第一次發出請求時,ETag 由服務器返回,其值爲該資源的標籤。當我們再次請求該資源時,If-None-Match 由客戶端發送,其保存了 ETag 的值。服務器收到請求後,將 If-None-Match 的值與被請求資源的標籤進行比對。若資源的標籤不等於 If-None-Match 的值,說明資源被修改過,則返回狀態碼 200 以及最新資源;若資源的標籤等於 If-None-Match 的值,說明資源無修改,則返回狀態碼 304,通知客戶端繼續使用緩存資源。

ETag / If-None-Match 組合的優先級高於 Last-Modified / If-Modified-Since 組合。

例子:

//第二次發出請求時,請求頭內容
If-None-Match: W/"5ce-164c641f628"

//第二次發出請求時,響應頭內容
ETag: W/"5ce-164c641f628"

//此時,狀態碼應該爲:
Status Code: 304 Not Modified

應用緩存機制

結合以上強制緩存和對比緩存的內容,我們可以大概繪製一份瀏覽器使用緩存的流程圖:

圖片描述


如有錯誤,歡迎指正,本人不勝感激。


轉載地址:http://www.imooc.com/article/288760

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