Web 緩存大體能夠分爲:數據庫緩存、服務器端緩存(代理服務器緩存、CDN 緩存)、瀏覽器緩存。node
瀏覽器緩存也包含不少內容: HTTP 緩存、indexDB、cookie、localstorage 等等。這裏咱們只討論 HTTP 緩存相關內容。數據庫
在具體瞭解 HTTP 緩存以前先來明確幾個術語:瀏覽器
瀏覽器緩存主要是 HTTP 協議定義的緩存機制。HTML meta 標籤,例如緩存
<META HTTP-EQUIV="Pragma" CONTENT="no-store">服務器
含義是讓瀏覽器不緩存當前頁面。可是代理服務器不解析 HTML 內容,通常應用普遍的是用 HTTP 頭信息控制緩存。cookie
瀏覽器緩存分類函數
瀏覽器緩存分爲強緩存和協商緩存,瀏覽器加載一個頁面的簡單流程以下:工具
強緩存url
命中強緩存時,瀏覽器並不會將請求發送給服務器。在Chrome的開發者工具中看到http的返回碼是200,可是在Size列會顯示爲(from cache)。
spa
強緩存是利用http的返回頭中的Expires或者Cache-Control兩個字段來控制的,用來表示資源的緩存時間。
Expires
緩存過時時間,用來指定資源到期的時間,是服務器端的具體的時間點。也就是說,Expires=max-age + 請求時間,須要和Last-modified結合使用。但在上面咱們提到過,cache-control的優先級更高。 Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過時時間前瀏覽器能夠直接從瀏覽器緩存取數據,而無需再次請求。
該字段會返回一個時間,好比Expires:Thu,31 Dec 2037 23:59:59 GMT。這個時間表明着這個資源的失效時間,也就是說在2037年12月31日23點59分59秒以前都是有效的,即命中緩存。這種方式有一個明顯的缺點,因爲失效時間是一個絕對時間,因此當客戶端本地時間被修改之後,服務器與客戶端時間誤差變大之後,就會致使緩存混亂。因而發展出了Cache-Control。
Cache-Control
Cache-Control是一個相對時間,例如Cache-Control:3600,表明着資源的有效期是3600秒。因爲是相對時間,而且都是與客戶端時間比較,因此服務器與客戶端時間誤差也不會致使問題。
Cache-Control與Expires能夠在服務端配置同時啓用或者啓用任意一個,同時啓用的時候Cache-Control優先級高。
Cache-Control 能夠由多個字段組合而成,主要有如下幾個取值:
1. max-age 指定一個時間長度,在這個時間段內緩存是有效的,單位是s。例如設置 Cache-Control:max-age=31536000,也就是說緩存有效期爲(31536000 / 24 / 60 * 60)天,第一次訪問這個資源的時候,服務器端也返回了 Expires 字段,而且過時時間是一年後。
在沒有禁用緩存而且沒有超過有效時間的狀況下,再次訪問這個資源就命中了緩存,不會向服務器請求資源而是直接從瀏覽器緩存中取。
2. s-maxage 同 max-age,覆蓋 max-age、Expires,但僅適用於共享緩存,在私有緩存中被忽略。
3. public 代表響應能夠被任何對象(發送請求的客戶端、代理服務器等等)緩存。
4. private 代表響應只能被單個用戶(多是操做系統用戶、瀏覽器用戶)緩存,是非共享的,不能被代理服務器緩存。
5. no-cache 強制全部緩存了該響應的用戶,在使用已緩存的數據前,發送帶驗證器的請求到服務器。不是字面意思上的不緩存。
6. no-store 禁止緩存,每次請求都要向服務器從新獲取數據。
七、must-revalidate指定若是頁面是過時的,則去服務器進行獲取。這個指令並不經常使用,就不作過多的討論了。
若未命中強緩存,則瀏覽器會將請求發送至服務器。服務器根據http頭信息中的Last-Modify/If-Modify-Since或Etag/If-None-Match來判斷是否命中協商緩存。若是命中,則http返回碼爲304,瀏覽器從緩存中加載資源。
Last-Modify/If-Modify-Since
瀏覽器第一次請求一個資源的時候,服務器返回的header中會加上Last-Modify,Last-modify是一個時間標識該資源的最後修改時間,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
當瀏覽器再次請求該資源時,發送的請求頭中會包含If-Modify-Since,該值爲緩存以前返回的Last-Modify。服務器收到If-Modify-Since後,根據資源的最後修改時間判斷是否命中緩存。
若是命中緩存,則返回http304,而且不會返回資源內容,而且不會返回Last-Modify。因爲對比的服務端時間,因此客戶端與服務端時間差距不會致使問題。可是有時候經過最後修改時間來判斷資源是否修改仍是不太準確(資源變化了最後修改時間也能夠一致)。因而出現了ETag/If-None-Match。
ETag/If-None-Match
與Last-Modify/If-Modify-Since不一樣的是,Etag/If-None-Match返回的是一個校驗碼(ETag: entity tag)。ETag能夠保證每個資源是惟一的,資源變化都會致使ETag變化*。ETag值的變動則說明資源狀態已經被修改。服務器根據瀏覽器上發送的If-None-Match值來判斷是否命中緩存。
ETag擴展說明
咱們對ETag寄予厚望,但願它對於每個url生成惟一的值,資源變化時ETag也發生變化。神祕的Etag是如何生成的呢?以Apache爲例,ETag生成靠如下幾種因子
你可能會以爲使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,爲何還須要Etag(實體標識)呢?HTTP1.1中Etag的出現主要是爲了解決幾個Last-Modified比較難解決的問題:
1. Last-Modified標註的最後修改只能精確到秒級,若是某些文件在1秒鐘之內,被修改屢次的話,它將不能準確標註文件的修改時間
2. 若是某些文件會被按期生成,當有時內容並無任何變化,但Last-Modified卻改變了,致使文件無法使用緩存
3.有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形
Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的惟一標識符,可以更加準確的控制緩存。Last-Modified與ETag是能夠一塊兒使用的,服務器會優先驗證ETag,一致的狀況下,纔會繼續比對Last-Modified,最後才決定是否返回304。
瀏覽器緩存行爲還有用戶的行爲有關!!!
用戶操做 |
Expires/Cache-Control |
Last-Modified/Etag |
地址欄回車 |
有效 |
有效 |
頁面連接跳轉 |
有效 |
有效 |
新開窗口 |
有效 |
有效 |
前進、後退 |
有效 |
有效 |
F5刷新 |
無效 |
有效 |
Ctrl+F5刷新 |
無效 |
無效 |
瀏覽器再次請求時: