瀏覽器緩存是瀏覽器在本地磁盤對用戶最近請求過的文檔進行存儲,當訪問者再次訪問同一頁面時,瀏覽器就能夠直接從本地磁盤加載文檔。html
因此根據上面的特色,瀏覽器緩存有下面的優勢:web
減小冗餘的數據傳輸瀏覽器
減小服務器負擔緩存
加快客戶端加載網頁的速度性能優化
瀏覽器緩存是Web性能優化的重要方式。那麼瀏覽器緩存的過程到底是怎麼樣的呢?服務器
在瀏覽器第一次發起請求時,本地無緩存,向web服務器發送請求,服務器起端響應請求,瀏覽器端緩存。過程以下:
併發
在第一次請求時,服務器會將頁面最後修改時間經過Last-Modified
標識由服務器發送給客戶端,客戶端記錄修改時間;服務器還會生成一個Etag,併發送給客戶端。性能
瀏覽器後續再次進行請求時:
學習
瀏覽器緩存主要分爲強強緩存(也稱本地緩存)和協商緩存(也稱弱緩存)。根據上圖,瀏覽器在第一次請求發生後,再次發送請求時:優化
瀏覽器請求某一資源時,會先獲取該資源緩存的header信息,而後根據header中的Cache-Control
和Expires
來判斷是否過時。若沒過時則直接從緩存中獲取資源信息,包括緩存的header的信息,因此這次請求不會與服務器進行通訊。這裏判斷是否過時,則是強緩存相關。後面會講Cache-Control
和Expires
相關。
若是顯示已過時,瀏覽器會向服務器端發送請求,這個請求會攜帶第一次請求返回的有關緩存的header字段信息,好比客戶端會經過If-None-Match
頭將先前服務器端發送過來的Etag發送給服務器,服務會對比這個客戶端發過來的Etag是否與服務器的相同,若相同,就將If-None-Match
的值設爲false,返回狀態304,客戶端繼續使用本地緩存,不解析服務器端發回來的數據,若不相同就將If-None-Match
的值設爲true,返回狀態爲200,客戶端從新機械服務器端返回的數據;客戶端還會經過If-Modified-Since
頭將先前服務器端發過來的最後修改時間戳發送給服務器,服務器端經過這個時間戳判斷客戶端的頁面是不是最新的,若是不是最新的,則返回最新的內容,若是是最新的,則返回304,客戶端繼續使用本地緩存。
強緩存是利用http頭中的Expires
和Cache-Control
兩個字段來控制的,用來表示資源的緩存時間。強緩存中,普通刷新會忽略它,但不會清除它,須要強制刷新。瀏覽器強制刷新,請求會帶上Cache-Control:no-cache
和Pragma:no-cache
Expires
是http1.0的規範,它的值是一個絕對時間的GMT格式的時間字符串。如我如今這個網頁的Expires
值是:expires:Fri, 14 Apr 2017 10:47:02 GMT
。這個時間表明這這個資源的失效時間,只要發送請求時間是在Expires
以前,那麼本地緩存始終有效,則在緩存中讀取數據。因此這種方式有一個明顯的缺點,因爲失效的時間是一個絕對時間,因此當服務器與客戶端時間誤差較大時,就會致使緩存混亂。若是同時出現Cache-Control:max-age
和Expires
,那麼max-age
優先級更高。如我主頁的response headers部分以下:
cache-control:max-age=691200 expires:Fri, 14 Apr 2017 10:47:02 GMT
那麼表示資源能夠被緩存的最長時間爲691200秒,會優先考慮max-age
。
Cache-Control是在http1.1中出現的,主要是利用該字段的max-age值來進行判斷,它是一個相對時間,例如Cache-Control:max-age=3600,表明着資源的有效期是3600秒。cache-control除了該字段外,還有下面幾個比較經常使用的設置值:
no-cache:不使用本地緩存。須要使用緩存協商,先與服務器確認返回的響應是否被更改,若是以前的響應中存在ETag,那麼請求的時候會與服務端驗證,若是資源未被更改,則能夠避免從新下載。
no-store:直接禁止遊覽器緩存數據,每次用戶請求該資源,都會向服務器發送一個請求,每次都會下載完整的資源。
public:能夠被全部的用戶緩存,包括終端用戶和CDN等中間代理服務器。
private:只能被終端用戶的瀏覽器緩存,不容許CDN等中繼緩存服務器對其緩存。
Cache-Control與Expires能夠在服務端配置同時啓用,同時啓用的時候Cache-Control優先級高。
協商緩存就是由服務器來肯定緩存資源是否可用,因此客戶端與服務器端要經過某種標識來進行通訊,從而讓服務器判斷請求資源是否能夠緩存訪問。
普通刷新會啓用弱緩存,忽略強緩存。只有在地址欄或收藏夾輸入網址、經過連接引用資源等狀況下,瀏覽器纔會啓用強緩存,這也是爲何有時候咱們更新一張圖片、一個js文件,頁面內容依然是舊的,可是直接瀏覽器訪問那個圖片或文件,看到的內容倒是新的。
這個主要涉及到兩組header字段:Etag
和If-None-Match
、Last-Modified
和If-Modified-Since
。上面以及說得很清楚這兩組怎麼使用啦~複習一下:
Etag
和If-None-Match
Etag/If-None-Match返回的是一個校驗碼。ETag能夠保證每個資源是惟一的,資源變化都會致使ETag變化。服務器根據瀏覽器上送的If-None-Match值來判斷是否命中緩存。
與Last-Modified不同的是,當服務器返回304 Not Modified的響應時,因爲ETag從新生成過,response header中還會把這個ETag返回,即便這個ETag跟以前的沒有變化。
瀏覽器第一次請求一個資源的時候,服務器返回的header中會加上Last-Modify,Last-modify是一個時間標識該資源的最後修改時間,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
當瀏覽器再次請求該資源時,request的請求頭中會包含If-Modify-Since,該值爲緩存以前返回的Last-Modify。服務器收到If-Modify-Since後,根據資源的最後修改時間判斷是否命中緩存。
若是命中緩存,則返回304,而且不會返回資源內容,而且不會返回Last-Modify。
你可能會以爲使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,爲何還須要Etag呢?HTTP1.1中Etag的出現主要是爲了解決幾個Last-Modified比較難解決的問題:
一些文件也許會週期性的更改,可是他的內容並不改變(僅僅改變的修改時間),這個時候咱們並不但願客戶端認爲這個文件被修改了,而從新GET;
某些文件修改很是頻繁,好比在秒如下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改沒法判斷(或者說UNIX記錄MTIME只能精確到秒);
某些服務器不能精確的獲得文件的最後修改時間。
Last-Modified與ETag是能夠一塊兒使用的,服務器會優先驗證ETag,一致的狀況下,纔會繼續比對Last-Modified,最後才決定是否返回304。
另外以爲一篇很好的文章,從緩存策略來學習HTTP緩存:HTTP基於緩存策略三要素分解法