瀏覽器緩存:強緩存和協商緩存


緩存是指代理服務器或客戶端磁盤內保存的資源副本。利用緩存可減少對服務器的訪問,因此也就節省了通信流量和通信時間。
瀏覽器緩存(Brower Caching)是瀏覽器在本地磁盤對用戶最近請求過的文檔進行存儲,當訪問者再次訪問同一頁面時,瀏覽器就可以直接從本地磁盤加載文檔。

瀏覽器緩存的優點有:

  1. 減少了冗余的數據傳輸,節省了網費
  2. 減少了服務器的負擔,大大提升了網站的性能
  3. 加快了客戶端加載網頁的速度

瀏覽器緩存分為強緩存和協商緩存

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

強緩存

強緩存是利用http的返回頭中的Expires或者Cache-Control兩個字段來控制的,用來表示資源的緩存時間。·

Expires
該字段是http1.0時的規范,它的值為一個絕對時間的GMT格式的時間字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT。這個時間代表着這個資源的失效時間,在此時間之前,即命中緩存。這種方式有一個明顯的缺點,由於失效時間是一個絕對時間,所以當服務器與客戶端時間偏差較大時,就會導致緩存混亂。

Cache-Control
Cache-Control是http1.1時出現的header信息,主要是利用該字段的max-age值來進行判斷,它是一個相對時間,例如Cache-Control:max-age=3600,代表着資源的有效期是3600秒。cache-control除了該字段外,還有下面幾個比較常用的設置值:

  • no-cache:不使用本地緩存。需要使用緩存協商,先與服務器確認返回的響應是否被更改,如果之前的響應中存在ETag,那么請求的時候會與服務端驗證,如果資源未被更改,則可以避免重新下載。
  • no-store:直接禁止游覽器緩存數據,每次用戶請求該資源,都會向服務器發送一個請求,每次都會下載完整的資源。
  • public:可以被所有的用戶緩存,包括終端用戶和CDN等中間代理服務器。
  • private:只能被終端用戶的瀏覽器緩存,不允許CDN等中繼緩存服務器對其緩存。

Cache-Control與Expires可以在服務端配置同時啟用,同時啟用的時候Cache-Control優先級高。

協商緩存

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

Last-Modify/If-Modify-Since

瀏覽器第一次請求一個資源的時候,服務器返回的header中會加上Last-Modified,Last-Modified是一個時間,標識該資源的最后修改時間,例如Last-Modified: Thu,31 Dec 2037 23:59:59 GMT。

當瀏覽器再次請求該資源時,request的請求頭中會包含If-Modified-Since,該值為緩存之前返回的Last-Modified。服務器收到If-Modified-Since后,根據資源的最后修改時間判斷是否命中緩存。

如果命中緩存,則返回304,並且不會返回資源內容,並且不會返回Last-Modified。

ETag/If-None-Match

與Last-Modified/If-Modified-Since不同的是,Etag/If-None-Match返回的是一個校驗碼。ETag可以保證每一個資源是唯一的,資源變化都會導致ETag變化。服務器根據瀏覽器發送的If-None-Match值來判斷是否命中緩存。

與Last-Modified不一樣的是,當服務器返回304 Not Modified的響應時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag跟之前的沒有變化。

為什么要有Etag

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

  • 一些文件也許會周期性的更改,但是他的內容並不改變(僅僅改變的修改時間),這個時候我們並不希望客戶端認為這個文件被修改了,而重新GET;
  • 某些文件修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒);
  • 某些服務器不能精確的得到文件的最后修改時間。

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

強緩存與協商緩存的區別可以用下表來表示:

緩存類型 獲取資源形式 狀態碼 發送請求到服務器
強緩存 從緩存取 200(from cache) 否,直接從緩存取
協商緩存 從緩存取 304(Not Modified) 是,通過服務器來告知緩存是否可用

用戶行為對緩存的影響

用戶操作 Expires/Cache-Control Last-Modied/Etag
地址欄回車 有效 有效
頁面鏈接跳轉 有效 有效
新開窗口 有效 有效
前進回退 有效 有效
F5刷新 無效 有效
Ctrl+F5強制刷新 無效 無效

實際問題分析

如文章開頭所述,代碼更新到線上后用戶瀏覽器不能自行更新,我們不能要求客戶在系統更新后都進行一次緩存清理的操作。

到底該如何解決呢?

在資源請求的URL中增加一個參數,比如:js/mian.js?ver=0.7.1。這個參數是一個版本號,每一次部署的時候變更一下,當這個參數變化的時候,強緩存都會失效並重新加載。這樣一來,靜態資源,部署以后就需要重新加載。這樣就比較完美的解決了問題。

附:
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM