一篇文章帶你理解HTTP緩存

爲何會有HTTP緩存?

HTTP緩存的存在是由於web前端的性能瓶頸大部分的緣由在於HTTP傳輸的時間耗費過長。若是可以減小這種HTTP請求的時間,對網頁的性能來講是很是大的提高,對於用戶的體驗也能獲得極大的改善。html

HTTP緩存標識

HTTP緩存可分爲強緩存(Cache-Control和Expires)以及協商緩存(Etag和Last-Modified)。前端

強緩存和協商緩存的區別在於:若是命中強緩存,會直接從緩存中讀取資源,不向服務器請求。協商緩存則會向服務器請求確認資源是否過時。這也是緩存驗證的順序,先使用強緩存,後使用協商緩存。web

下面則簡單介紹一下這兩種緩存類型的標識瀏覽器

Cache-Control

Cache-Control設置有效期max-age的值是時間的相對值。緩存

下面則簡單介紹Cache-Control經常使用的使用值:性能優化

value description
public 代表響應能夠被任何對象(包括:發送請求的客戶端,代理服務器,等等)緩存。
private 代表響應只能被單個用戶緩存,不能做爲共享緩存(即代理服務器不能緩存它),能夠緩存響應內容。
no-cache 在發佈緩存副本以前,強制高速緩存將請求提交給原始服務器進行驗證。
no-store 緩存不該存儲有關客戶端請求或服務器響應的任何內容。
max-age=<seconds> 設置緩存存儲的最大週期,超過這個時間緩存被認爲過時(單位秒)。與Expires相反,時間是相對於請求的時間。
must-revalidate 緩存必須在使用以前驗證舊資源的狀態,而且不可以使用過時資源。
proxy-revalidate 與must-revalidate做用相同,但它僅適用於共享緩存(例如代理),並被私有緩存忽略。

若想了解更詳細的說明,可參考此連接:developer.mozilla.org/zh-CN/docs/…bash

Expires

Expires 響應頭包含日期/時間, 即在此時候以後,響應過時。服務器

Expires設置的值是一個絕對值。前端性能

Expires: Wed, 21 Oct 2015 07:28:00 GMT
複製代碼

Etag

Etag HTTP響應頭是資源的特定版本的標識符。這可讓緩存更高效,並節省帶寬,由於若是內容沒有改變,Web服務器不須要發送完整的響應。而若是內容發生了變化,使用ETag有助於防止資源的同時更新相互覆蓋(「空中碰撞」)。性能

Etag的值是根據資源文件內容生成的一個hash值。

Etag: 33a64df551425fcc55e4d42a148795d9f25f89d4
複製代碼

Last-Modified

Last-Modified包含源頭服務器認定的資源作出修改的日期及時間。 它一般被用做一個驗證器來判斷接收到的或者存儲的資源是否彼此一致。因爲精確度比 ETag 要低,因此這是一個備用機制。

Last-Modified的值是一個時間的絕對值。

Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
複製代碼

HTTP緩存驗證規則

HTTP緩存的驗證順序

  1. 先使用強緩存(Cache-Control > Expires) 判斷資源是否過時;
  2. 若資源未過時則直接從緩存讀取,若資源過時則使用協商緩存;
  3. 使用協商緩存(Etag > Last-Modified)請求服務器確認資源有無修改(請求頭會帶上 If-None-Match 或 If-Modified-Since);
  4. 若資源無修改則返回 304 狀態碼告訴客戶端可讀取緩存;若資源已修改則返回 200 狀態碼從新獲取資源;

圖示:

圖片來源: www.cnblogs.com/xiaohuochai…

HTTP緩存驗證說明

如下的HTTP緩存驗證說明是基於假設請求存在4個緩存頭標記;

  1. HTTP緩存是否過時,先判斷Cache-Control是否設置max-ages-max-age,若是已設置則忽略Expires而且驗證是否過時,不然驗證Expires是否過時;其實按照MDN文檔的說明,Last-Modified也是能夠計算出一個緩存時間;

下面是MDN文檔的說明:

對於含有特定頭信息的請求,會去計算緩存壽命。好比Cache-control: max-age=N的頭,相應的緩存的壽命就是N。一般狀況下,對於不含這個屬性的請求則會去查看是否包含Expires屬性,經過比較Expires的值和頭裏面Date屬性的值來判斷是否緩存還有效。若是max-age和expires屬性都沒有,找找頭裏的Last-Modified信息。若是有,緩存的壽命就等於頭裏面Date的值減去Last-Modified的值除以10(注:根據rfc2626其實也就是乘以10%)。

緩存時間計算公式:

expirationTime = responseTime + freshnessLifetime - currentAge

  1. 若是該緩存未過時,是不會向服務器發送請求的,而是直接從緩存中讀取,也就是咱們能夠從HTTP請求信息裏獲得的狀態碼 200 (from cache memory || from disk memory) ,若是緩存過時,則使用協商緩存;
  • 先嚐試從內存中讀取,再嘗試從硬盤中讀取。
  • 200 form memory cache 不訪問服務器,通常已經加載過該資源且緩存在了內存當中,直接從內存中讀取緩存。瀏覽器關閉後,數據將不存在(資源被釋放掉了),再次打開相同的頁面時,不會出現from memory cache。
  • 200 from disk cache 不訪問服務器,已經在以前的某個時間加載過該資源,直接從硬盤中讀取緩存,關閉瀏覽器後,數據依然存在,此資源不會隨着該頁面的關閉而釋放掉下次打開仍然會是from disk cache。
  1. 使用協商緩存驗證緩存資源是否修改;Etag > Last-Modified,當存在Etag則使用Etag,不然使用Last-Modified;而且請求時會帶上特定的標識;
  • Etag 請求時會帶上 If-None-Match
  • Last-Modified 請求時會帶上 If-Modified-Since
  1. 當確認資源未修改時則返回 304 (Not Modified)告訴客戶端能夠繼續使用緩存,不然返回200從新獲取新的資源。

HTTP緩存早期的時候只有Expires和Last-Modified,爲何後面又會出現Cache-Control和Etag呢?

先說說Expires和Cache-Control,Expires的值是一個準確的時間,比較的時候先根據返回頭的Date值比較判斷,可是若無Date頭信息返回則是根據客戶端的本地時間進行比較;本地時間由於各類因素影響,會存在各類不一樣的值,致使Expires緩存的時間並非咱們想要的效果。而Cache-Control設置max-age使用的相對值則相對來講控制粒度更精確了;而且Cache-Control的其餘值則讓咱們對於緩存的控制更加靈活。

再說說Last-Modified和Etag,Last-Modified的值也是一個準確的時間,精確到秒;使用時間來判斷資源是否修改則可能存在如下問題:

  1. 1秒內的修改可能不被檢查到,致使緩存沒法更新;
  2. 資源可能只是多了幾個空格或無變化,可是Last-Modified的時間已經變化;

針對以上的問題因此有了Etag的存在,Etag是根據資源內容生成的hash值對比判斷資源是否更新,控制粒度比Last-Modified更加精確。

總結

HTTP緩存的本質上是以空間換時間,緩存的存在是爲了儘量的減小HTTP請求次數和HTTP傳輸的內容大小,這也是前端性能優化中重要的一環。合理的設置頁面資源的緩存,有助你提高頁面的體驗。

相關文章
相關標籤/搜索