瀏覽器緩存機制,其實主要就是HTTP協議定義的緩存機制(如: Expires; Cache-control等)。可是也有非HTTP協議定義的緩存機制,如使用HTML Meta 標籤,Web開發者能夠在HTML頁面的<head>節點中加入<meta>標籤,代碼以下:css
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
上述代碼的做用是告訴瀏覽器當前頁面不被緩存,每次訪問都須要去服務器拉取。使用上很簡單,但只有部分瀏覽器能夠支持,並且全部緩存代理服務器都不支持,由於代理不解析HTML內容自己。下面主要介紹HTTP協議定義的緩存機制。html
瀏覽器緩存一直是一個讓人又愛又恨的存在,一方面極大地提高了用戶體驗,而另外一方面有時會由於讀取了緩存而展現了「錯誤」的東西,而在開發過程當中想方設法地想把緩存禁掉。若是沒據說過瀏覽器緩存或者不知道瀏覽器緩存的用處,能夠先瀏覽一下這篇文章->Web緩存的做用與類型 。jquery
那麼瀏覽器緩存機制究竟是如何工做的呢?核心就是把緩存的內容保存在了本地,而不用每次都向服務端發送相同的請求,設想下每次都打開相同的頁面,而在第一次打開的同時,將下載的js、css、圖片等「保存」在了本地,而以後的請求每次都在本地讀取,效率是否是高了不少?真正的瀏覽器工做的時候並非將完整的內容保存在本地,各類瀏覽器都有不一樣的方式,譬如firefox是一種相似innodb的方式存儲的key value 的模式,在地址欄中輸入 about:cache 能夠看見緩存的文件,chrome會把緩存的文件保存在一個叫User Data的文件夾下。可是若是每次都讀取緩存也會存在必定的問題,若是服務端的文件更新了呢?這時服務端就會和客戶端約定一個有效期,譬如說服務端告訴客戶端1天內我服務端的文件不會更新,你就放心地讀取緩存吧,因而在這一天裏每次遇到相同的請求客戶端都開心地能夠讀取緩存裏的文件。可是若是一天過去了,客戶端又要讀取該文件了,發現和服務端約定的有效期過了,因而就會向服務端發送請求,試圖下載一個新的文件,可是頗有可能服務端的文件其實並無更新,其實仍是能夠讀取緩存的。這時該怎麼判斷服務端的文件有沒有更新呢?有兩種方式,第一種在上一次服務端告訴客戶端約定的有效期的同時,告訴客戶端該文件最後修改的時間,當再次試圖從服務端下載該文件的時候,check下該文件有沒有更新(對比最後修改時間),若是沒有,則讀取緩存;第二種方式是在上一次服務端告訴客戶端約定有效期的同時,同時告訴客戶端該文件的版本號,當服務端文件更新的時候,改變版本號,再次發送請求的時候check一下版本號是否一致就好了,如一致,則可直接讀取緩存。web
而事實上真正的瀏覽器緩存機制大抵也是如此,接下來就能夠分別對號入座了。chrome
須要注意的是,瀏覽器會在第一次請求完服務器後獲得響應,咱們能夠在服務器中設置這些響應,從而達到在之後的請求中儘可能減小甚至不從服務器獲取資源的目的。瀏覽器是依靠請求和響應中的的頭信息來控制緩存的。瀏覽器
Expires和Cache-Control就是服務端用來約定和客戶端的有效時間的。緩存
好比如上一個響應頭,Expires規定了緩存失效時間(Date爲當前時間),而Cache-Control的max-age規定了緩存有效時間(2552s),理論上這兩個值計算出的有效時間應該是相同的(上圖好像不一致)。Expires是HTTP1.0的東西,而Cache-Control是HTTP1.1的,規定若是max-age和Expires同時存在,前者優先級高於後者。Cache-Control的參數能夠設置不少值,譬如(參考瀏覽器緩存機制):安全
而Last-Modified/If-Modified-Since就是上面說的當有效期事後,check服務端文件是否更新的第一種方式,要配合Cache-Control使用。好比第一次訪問個人主頁simplify the life,會請求一個jquery文件,響應頭返回以下信息:服務器
而後我在主頁按下ctrl+r刷新,由於ctrl+r會默認跳過max-age和Expires的檢驗直接去向服務器發送請求(下文再探討各類刷新後如何讀取緩存),咱們看看請求截圖:post
請求頭中包含了If-Modified-Since項,而它的值和上次請求響應頭中的Last-Modified一致,咱們發現這個日期是在遙遠的2013年,也就是說這個jquery文件自從2013年的那個日期後就沒有再被修改過了。將If-Modified-Since的日期和服務端該文件的最後修改日期對比,若是相同,則響應HTTP304,從緩存讀數據;若是不相同文件更新了,HTTP200,返回數據,同時經過響應頭更新last-Modified的值(以備下次對比)。
而ETag/If-None-Match則是上文大話中說的第二種check服務端文件是否更新的方式,也要配合Cache-Control使用。實際上ETag並非文件的版本號,而是一串能夠表明該文件惟一的字符串(Apache中,ETag的值,默認是對文件的索引節(INode),大小(Size)和最後修改時間(MTime)進行Hash後獲得的。),當客戶端發現和服務器約定的直接讀取緩存的時間過了,就在請求中發送If-None-Match選項,值即爲上次請求後響應頭的ETag值,該值在服務端和服務端表明該文件惟一的字符串對比(若是服務端該文件改變了,該值就會變),若是相同,則相應HTTP304,客戶端直接讀取緩存,若是不相同,HTTP200,下載正確的數據,更新ETag值。
看如上截圖,與服務器約定的直接讀取本地緩存的時間過了,就會向服務器發送新的請求,請求頭中帶If-None-Match項,該字符串值會在服務端進行匹配,很顯然,並無什麼變化(看響應頭的ETag值),因而響應HTTP304,直接讀取緩存。或許你會發送該請求也有If-Modified-Since項,若是二者同時存在,If-None-Match優先,忽略If-Modified-Since。或許你會問爲何它優先?二者功能類似甚至相同,爲何要同時存在?HTTP1.1中ETag的出現主要是爲了解決幾個Last-Modified比較難解決的問題:
固然並非全部請求都能被緩存。
沒法被瀏覽器緩存的請求:
瀏覽器緩存過程還和用戶行爲有關,譬如上面提到的,打開個人主頁simplify the life,有個jquery的請求,若是直接在地址欄按回車,響應HTTP200(from cache),由於有效期還沒過直接讀取的緩存;若是ctrl+r進行刷新,則會相應HTTP304(Not Modified),雖然仍是讀取的本地緩存,可是多了一次服務端的請求;而若是是ctrl+shift+r強刷,則會直接從服務器下載新的文件,響應HTTP200。
經過上表咱們能夠看到,當用戶在按F5進行刷新的時候,會忽略Expires/Cache-Control的設置,會再次發送請求去服務器請求,而Last-Modified/Etag仍是有效的,服務器會根據狀況判斷返回304仍是200;而當用戶使用Ctrl+F5進行強制刷新的時候,只是全部的緩存機制都將失效,從新從服務器拉去資源。
更多能夠參考瀏覽器緩存機制
盜圖瀏覽器緩存機制,兩張圖很清晰
http://www.cnblogs.com/zichi/p/4685822.html