HTTP 強緩存和協商緩存介紹


概述

瀏覽器緩存,既是網頁性能優化里面靜態資源相關優化的一大利器,也是無數web開發人員在工作過程不可避免的一大問題,所以在產品開發的時候我們總是想辦法避免緩存產生,而在產品發布之時又在想策略管理緩存提升網頁的訪問速度。了解瀏覽器的緩存命中原理,是開發web應用的基礎,本文着眼於此。

基本認知

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

  1. 瀏覽器在加載資源時,先根據這個資源的一些http header判斷它是否命中強緩存,強緩存如果命中,瀏覽器直接從自己的緩存中讀取資源,不會發請求到服務器,此請求返回的http狀態為200,在chrome的開發者工具的network里面size會顯示為from cache。

  2. 當強緩存沒有命中的時候,瀏覽器一定會發送一個請求到服務器,通過服務器端依據資源的另外一些http header驗證這個資源是否命中協商緩存,如果協商緩存命中,服務器會將這個請求返回,並且狀態碼為304,不會返回這個資源的數據,而是告訴客戶端可以直接從緩存中加載這個資源,於是瀏覽器就又會從自己的緩存中去加載這個資源;

  3. 當協商緩存也沒有命中的時候,瀏覽器直接從服務器加載資源數據。

強緩存與協商緩存的共同點是:如果命中,都是從客戶端緩存中加載資源,而不是從服務器加載資源數據;區別是:強緩存不發請求到服務器,協商緩存會發請求到服務器。

強緩存原理

強緩存是利用Expires或者Cache-Control這兩個http response header實現的,它們都用來表示資源在客戶端緩存的有效期。Expires是http1.0提出的一個表示資源過期時間的header,而Cache-Control則是http1.1提出的,如果同時存在則以Cache-Control為先。如下圖

Expires:Sat, 01 Apr 2017 15:53:40 GMT其實意味着在東八區2017/04/01 23:53:40的時候此資源過期。而Cache-Control:max-age=864000意味着從Date:Wed, 22 Mar 2017 15:53:40 GMT這個日期開始算往后10天則資源過期,這個時間在這里實際上就等同於Expires的時間。

Expires是較老的強緩存管理header,由於它是服務器返回的一個絕對時間,在服務器時間與客戶端時間相差較大時,緩存管理容易出現問題,比如隨意修改下客戶端時間,就能影響緩存命中的結果。而Cache-Control是相對時間就不會有這種問題,兩個請求頭都加上也是為了兼容不支持http1.1的終端或者路由器。

協商緩存原理

當瀏覽器對某個資源的請求沒有命中強緩存,就會發一個請求到服務器,驗證協商緩存是否命中,如果協商緩存命中,請求響應返回的http狀態為304並且會顯示一個Not Modified的字符串,並且讓瀏覽器就又從自己的緩存中去加載這個資源。

協商緩存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】這兩對Header來管理的。

Last-Modified,If-Modified-Since

  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也就不會改變

如果協商緩存沒有命中,瀏覽器直接從服務器加載資源時,Last-Modified Header在重新加載的時候會被更新,下次請求時,If-Modified-Since會啟用上次返回的Last-Modified值。

有時候也會服務器上資源其實有變化,但是最后修改時間卻沒有變化的情況,就會影響協商緩存的可靠性。所以就有了另外一對header來管理協商緩存,這對header就是【ETag、If-None-Match】

ETag和If-None-Match

瀏覽器第一次跟服務器請求一個資源,會在respone的header加上ETag響應頭,這是服務器根據當前請求的資源生成的一個唯一標識,只要資源有變化這個串就不同,只要資源有變化這個串就不同,跟最后修改時間沒有關系,所以能很好的補充Last-Modified的問題

瀏覽器再次跟服務器請求這個資源時,在request的header上加上If-None-Match的header,這個header的值就是上一次請求時返回的ETag的值。

服務器再次收到資源請求時,根據瀏覽器傳過來If-None-Match和然后再根據資源生成一個新的ETag,如果這兩個值相同就說明資源沒有變化,否則就是有變化;如果沒有變化則返回304 Not Modified,但是不會返回資源內容;如果有變化,就正常返回資源內容。與Last-Modified不一樣的是,當服務器返回304 Not Modified的響應時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag跟之前的沒有變化

緩存管理

協商緩存需要配合強緩存使用,你看前面這個截圖中,除了Last-Modified這個header,還有強緩存的相關header,因為如果不啟用強緩存的話,協商緩存根本沒有意義。

如果資源已經被瀏覽器緩存下來,在緩存失效之前,再次請求時,默認會先檢查是否命中強緩存,如果強緩存命中則直接讀取緩存,如果強緩存沒有命中則發請求到服務器檢查是否命中協商緩存,如果協商緩存命中,則告訴瀏覽器還是可以從緩存讀取,否則才從服務器返回最新的資源。這是默認的處理方式,這個方式可能被瀏覽器的行為改變:

  • 當win上ctrl+f5、mac上command+shift+R來強制刷新網頁時,直接從服務器加載,跳過強緩存和協商緩存;

參考

瀏覽器緩存知識小結及應用


免責聲明!

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



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