瀏覽器緩存機制詳解

     對於瀏覽器緩存,相信很多開發者對它真的是又愛又恨。一方面極大地提升了用戶體驗,而另一方面有時會因爲讀取了緩存而展示了“錯誤”的東西,而在開發過程中千方百計地想把緩存禁掉。那麼瀏覽器緩存究竟是個什麼樣的神奇玩意呢?

什麼是瀏覽器緩存:

  簡單來說,瀏覽器緩存就是把一個已經請求過的Web資源(如html頁面,圖片,js,數據等)拷貝一份副本儲存在瀏覽器中。緩存會根據進來的請求保存輸出內容的副本。當下一個請求來到的時候,如果是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,還是向源服務器再次發送請求。比較常見的就是瀏覽器會緩存訪問過網站的網頁,當再次訪問這個URL地址的時候,如果網頁沒有更新,就不會再次下載網頁,而是直接使用本地緩存的網頁。只有當網站明確標識資源已經更新,瀏覽器纔會再次下載網頁。至於瀏覽器和網站服務器是如何標識網站頁面是否更新的機制,將在後面介紹。

  上圖就是使用了緩存的栗子,在頁面請求之後,web資源都被緩存了,在後面的重複請求中,可以看到許多資源都是直接從緩存中讀取的(from cache),而不是重新去向服務器請求。

 

爲什麼使用緩存:

(1)減少網絡帶寬消耗

  無論對於網站運營者或者用戶,帶寬都代表着金錢,過多的帶寬消耗,只會便宜了網絡運營商。當Web緩存副本被使用時,只會產生極小的網絡流量,可以有效的降低運營成本。

(2)降低服務器壓力

  給網絡資源設定有效期之後,用戶可以重複使用本地的緩存,減少對源服務器的請求,間接降低服務器的壓力。同時,搜索引擎的爬蟲機器人也能根據過期機制降低爬取的頻率,也能有效降低服務器的壓力。

(3)減少網絡延遲,加快頁面打開速度

  帶寬對於個人網站運營者來說是十分重要,而對於大型的互聯網公司來說,可能有時因爲錢多而真的不在乎。那Web緩存還有作用嗎?答案是肯定的,對於最終用戶,緩存的使用能夠明顯加快頁面打開速度,達到更好的體驗。

 

瀏覽器端的緩存規則:

  對於瀏覽器端的緩存來講,這些規則是在HTTP協議頭和HTML頁面的Meta標籤中定義的。他們分別從新鮮度校驗值兩個維度來規定瀏覽器是否可以直接使用緩存中的副本,還是需要去源服務器獲取更新的版本。

  新鮮度(過期機制):也就是緩存副本有效期。一個緩存副本必須滿足以下條件,瀏覽器會認爲它是有效的,足夠新的:

    1. 含有完整的過期時間控制頭信息(HTTP協議報頭),並且仍在有效期內;

    2. 瀏覽器已經使用過這個緩存副本,並且在一個會話中已經檢查過新鮮度;

  滿足以上兩個情況的一種,瀏覽器會直接從緩存中獲取副本並渲染。

  校驗值(驗證機制):服務器返回資源的時候有時在控制頭信息帶上這個資源的實體標籤Etag(Entity Tag),它可以用來作爲瀏覽器再次請求過程的校驗標識。如過發現校驗標識不匹配,說明資源已經被修改或過期,瀏覽器需求重新獲取資源內容。

 

瀏覽器緩存的控制:

  (1)使用HTML Meta 標籤

  Web開發者可以在HTML頁面的<head>節點中加入<meta>標籤,代碼如下

<meta http-equiv="Pragma" content="no-cache">  
<!- Pragma是http1.0版本中給客戶端設定緩存方式之一,具體作用會在後面詳細介紹 -->

  上述代碼的作用是告訴瀏覽器當前頁面不被緩存,每次訪問都需要去服務器拉取。但是!這裏有個坑...

  事實上這種禁用緩存的形式用處很有限:

    a. 僅有IE才能識別這段meta標籤含義,其它主流瀏覽器僅識別“Cache-Control: no-store”的meta標籤。

    b. 在IE中識別到該meta標籤含義,並不一定會在請求字段加上Pragma,但的確會讓當前頁面每次都發新請求(僅限頁面,頁面上的資源則不受影響)

  (2)使用緩存有關的HTTP消息報頭

  在這裏就需要先跟大家介紹一下HTTP的相關知識。一個URI的完整HTTP協議交互過程是由HTTP請求和HTTP響應組成的。有關HTTP詳細內容可參考《Hypertext Transfer Protocol — HTTP/1.1》、《HTTP協議詳解》等。

  在HTTP請求和響應的消息報頭中,常見的與緩存有關的消息報頭有:

規則消息包頭值/示例類型作用
新鮮度Pragmano-cache響應告訴瀏覽器忽略資源的緩存副本,每次訪問都需要去服務器拉取【http1.0中存在的字段,在http1.1已被拋棄,使用Cache-Control替代,但爲了做http協議的向下兼容,很多網站依舊會帶上這個字段】
 Expires Mon, 15 Aug 2016 03:56:47 GMT響應啓用緩存和定義緩存時間。告訴瀏覽器資源緩存過期時間,如果還沒過該時間點則不發請【http1.0中存在的字段,該字段所定義的緩存時間是相對服務器上的時間而言的,如果客戶端上的時間跟服務器上的時間不一致(特別是用戶修改了自己電腦的系統時間),那緩存時間可能就沒啥意義了。在HTTP 1.1版開始,使用Cache-Control: max-age=秒替代】
  Cache-Controlno-cache 響應告訴瀏覽器忽略資源的緩存副本,強制每次請求直接發送給服務器,拉取資源,但不是“不緩存”
  no-store響應 強制緩存在任何情況下都不要保留任何副本
   max-age=[秒]響應指明緩存副本的有效時長,從請求時間開始到過期時間之間的秒數
   public響應任何路徑的緩存者(本地緩存、代理服務器),可以無條件的緩存改資源
   private響應只針對單個用戶或者實體(不同用戶、窗口)緩存資源
  Last-ModifiedMon, 15 Aug 2016 03:56:47 GMT響應告訴瀏覽器這個資源最後的修改時間。服務器將資源傳遞給客戶端時,會將資源最後更改的時間以“Last-Modified: GMT”的形式加在實體首部上一起返回給客戶端【只能精確到秒級,如果某些文件在1秒鐘以內,被修改多次的話,它將不能準確標註文件的修改時間
  If-Modified-SinceMon, 15 Aug 2016 03:56:47 GMT 請求其值爲上次響應頭的Last-Modified值,再次向web服務器請求時帶上頭If-Modified-Since。web服務器收到請求後發現有頭If-Modified-Since則與被請求資源的最後修改時間進行比對。若最後修改時間較新,說明資源又被改動過,則響應整片資源內容(寫在響應消息包體內),包括更新Last-Modified的值,HTTP 200;若最後修改時間較舊,說明資源無新修改,則響應HTTP 304(無需包體,節省瀏覽),告知瀏覽器繼續使用所保存的cache
校驗值ETag"fd56273325a2114818df4f29a628226d" 響應告訴瀏覽器當前資源在服務器的唯一標識符(生成規則又服務器決定)
 If-None-Match "fd56273325a2114818df4f29a628226d"請求當資源過期時(使用Cache-Control標識的max-age),發現資源具有Etage聲明,則再次向web服務器請求時帶上頭If-None-Match(Etag的值)。web服務器收到請求後發現有頭If-None-Match則與被請求資源的相應校驗串進行比對,決定返回200或304

   在我們對HTTP請求頭和響應頭的部分字段有了一定的認識之後,我們接下來就來討論不同字段之間的關係和區別:

  · Cache-Control與Expires

  Cache-Control與Expires的作用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據還是重新發請求到服務器取數據。只不過Cache-Control的選擇更多,設置更細緻,如果同時設置的話,其優先級高於Expires

  · Last-Modified/ETag與Cache-Control/Expires

  配置Last-Modified/ETag的情況下,瀏覽器再次訪問統一URI的資源,還是會發送請求到服務器詢問文件是否已經修改,如果沒有,服務器會只發送一個304回給瀏覽器,告訴瀏覽器直接從自己本地的緩存取數據;如果修改過那就整個數據重新發給瀏覽器;

  Cache-Control/Expires則不同,如果檢測到本地的緩存還是有效的時間範圍內,瀏覽器直接使用本地副本,不會發送任何請求。兩者一起使用時,Cache-Control/Expires的優先級要高於Last-Modified/ETag。即當本地副本根據Cache-Control/Expires發現還在有效期內時,則不會再次發送請求去服務器詢問修改時間(Last-Modified)或實體標識(Etag)了。

  一般情況下,使用Cache-Control/Expires會配合Last-Modified/ETag一起使用,因爲即使服務器設置緩存時間, 當用戶點擊“刷新”按鈕時,瀏覽器會忽略緩存繼續向服務器發送請求,這時Last-Modified/ETag將能夠很好利用304,從而減少響應開銷。

   · Last-Modified與ETag

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

  1. Last-Modified標註的最後修改只能精確到秒級,如果某些文件在1秒鐘以內,被修改多次的話,它將不能準確標註文件的新鮮度
  2. 如果某些文件會被定期生成,當有時內容並沒有任何變化,但Last-Modified卻改變了,導致文件沒法使用緩存
  3. 有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形

Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符,能夠更加準確的控制緩存。Last-Modified與ETag是可以一起使用的,服務器會優先驗證ETag,一致的情況下,纔會繼續比對Last-Modified,最後才決定是否返回304。Etag的服務器生成規則和強弱Etag的相關內容可以參考,《互動百科-Etag》和《HTTP Header definition》,這裏不再深入。

  注意:

  1. Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符,能夠更加準確的控制緩存,但是需要注意的是分佈式系統裏多臺機器間文件的last-modified必須保持一致,以免負載均衡到不同機器導致比對失敗,Yahoo建議分佈式系統儘量關閉掉Etag(每臺機器生成的etag都會不一樣,因爲除了 last-modified、inode 也很難保持一致)。

   2. Last-Modified/If-Modified-Since要配合Cache-Control使用,Etag/If-None-Match也要配合Cache-Control使用。

 

瀏覽器HTTP請求流程:

  第一次請求:

  

  再次請求:

  

 

用戶行爲與緩存:

   瀏覽器緩存行爲還有用戶的行爲有關,具體情況如下:

用戶操作Expires/Cache-ControlLast-Modified/Etag
地址欄回車有效有效
頁面鏈接跳轉有效有效
新開窗口有效有效
前進、後退有效有效
F5刷新無效(BR重置max-age=0)有效
Ctrl+F5刷新無效(重置Cache-Control=no-cache)無效(請求頭丟棄該選項

 

不能緩存的請求:

  當然並不是所有請求都能被緩存,無法被瀏覽器緩存的請求如下:

    1. HTTP信息頭中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或Cache-Control:max-age=0等告訴瀏覽器不用緩存的請求

    2. 需要根據Cookie,認證信息等決定輸入內容的動態請求是不能被緩存的

    3. 經過HTTPS安全加密的請求(有人也經過測試發現,ie其實在頭部加入Cache-Control:max-age信息,firefox在頭部加入Cache-Control:Public之後,能夠對HTTPS的資源進行緩存,參考《HTTPS的七個誤解》)

    4. POST請求無法被緩存

    5. HTTP響應頭中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的請求無法被緩存

 

參考資料:

1. http://www.cnblogs.com/520yang/articles/4807408.html  瀏覽器 HTTP 協議緩存機制詳解

2. https://my.oschina.net/leejun2005/blog/369148  瀏覽器 HTTP 協議緩存機制詳解

3. http://web.jobbole.com/82997/  瀏覽器緩存機制淺析

4. http://www.alloyteam.com/2012/03/web-cache-2-browser-cache/  Web瀏覽器的緩存機制 

5. http://www.cnblogs.com/vajoy/p/5341664.html  淺談瀏覽器http的緩存機制

6. http://mp.weixin.qq.com/s/yf0pWRFM7v9Ru3D9_JhGPQ  瀏覽器緩存機制剖析

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