客戶端緩存
客戶端側緩存一般指的是瀏覽器緩存,目的就是加速各種靜態資源的訪問,想想現在的大型網站,隨便一個頁面都是一兩百個請求,每天 pv 都是億級別,如果沒有緩存,用戶體驗會急劇下降、同時服務器壓力和網絡帶寬都面臨嚴重的考驗。
客戶端緩存主要是HTTP協議定義的緩存機制(如 Expires, Cache-Control字段), 也有非HTTP協議定義的緩存,使用HTTP-MATE標簽
如
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
- 1
上述代碼的作用是告訴瀏覽器當前頁面不被緩存,每次訪問都需要去服務器拉取。使用上很簡單,但只有部分瀏覽器可以支持,而且所有緩存代理服務器都不支持,因為代理不解析HTML內容本身。
Expires策略
Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器緩存取數據,而無需再次請求。
Date頭域表示消息發送的時間,時間的描述格式由rfc822定義。例如,Date: Mon,31 Dec 2001 04:25:57GMT。
Web服務器告訴瀏覽器在2012-11-28 03:30:01這個時間點之前,可以使用緩存文件。發送請求的時間是2012-11-28 03:25:01,即緩存5分鍾。
不過Expires 是HTTP 1.0的東西,現在默認瀏覽器均默認使用HTTP 1.1,所以它的作用基本忽略。
Cache-Control策略
Cache-Control與Expires的作用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據還是重新發請求到服務器取數據。只不過Cache-Control的選擇更多,設置更細致,如果同時設置的話,其優先級高於Expires。
HTTP-Header中的Cache-Control字段:
可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age
各個消息中的指令含義如下:
-
public指示響應可被任何緩存區緩存。
-
private指示對於單個用戶的整個或部分響應消息,不能被共享緩存處理。這允許服務器僅僅描述當用戶的部分響應消息,此響應消息對於其他用戶的請求無效。
-
no-cache指示請求或響應消息不能緩存
-
no-store用於防止重要的信息被無意的發布。在請求消息中發送將使得請求和響應消息都不使用緩存。
-
max-age指示客戶機可以接收生存期不大於指定時間(以秒為單位)的響應。
-
min-fresh指示客戶機可以接收響應時間小於當前時間加上指定時間的響應。
-
max-stale指示客戶機可以接收超出超時期間的響應消息。如果指定max-stale消息的值,那么客戶機可以接收超出超時期指定值之內的響應消息。
還是上面那個請求,web服務器返回的Cache-Control頭的值為max-age=300,即5分鍾(和上面的Expires時間一致,這個不是必須的)。
需配合Cache-Control使用的字段
Last-Modified/If-Modified-Since
Last-Modified/If-Modified-Since要配合Cache-Control使用。
-
Last-Modified:標示這個響應資源的最后修改時間。web服務器在響應請求時,告訴瀏覽器資源的最后修改時間。
-
If-Modified-Since:當資源過期時(使用Cache-Control標識的max-age),發現資源具有Last-Modified聲明,則再次向web服務器請求時帶上頭 If-Modified-Since,表示請求時間。web服務器收到請求后發現有頭If-Modified-Since 則與被請求資源的最后修改時間進行比對。若最后修改時間較新,說明資源又被改動過,則響應整片資源內容(寫在響應消息包體內),HTTP 200;若最后修改時間較舊,說明資源無新修改,則響應HTTP 304 (無需包體,節省瀏覽),告知瀏覽器繼續使用所保存的cache。
Etag/If-None-Match
Etag/If-None-Match也要配合Cache-Control使用。
-
Etag:web服務器響應請求時,告訴瀏覽器當前資源在服務器的唯一標識(生成規則由服務器覺得)。Apache中,ETag的值,默認是對文件的索引節(INode),大小(Size)和最后修改時間(MTime)進行Hash后得到的。
-
If-None-Match:當資源過期時(使用Cache-Control標識的max-age),發現資源具有Etage聲明,則再次向web服務器請求時帶上頭If-None-Match (Etag的值)。web服務器收到請求后發現有頭If-None-Match 則與被請求資源的相應校驗串進行比對,決定返回200或304。
既生Last-Modified何生Etag?
你可能會覺得使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,為什么還需要Etag(實體標識)呢?HTTP1.1中Etag的出現主要是為了解決幾個Last-Modified比較難解決的問題:
-
Last-Modified標注的最后修改只能精確到秒級,如果某些文件在1秒鍾以內,被修改多次的話,它將不能准確標注文件的修改時間
-
如果某些文件會被定期生成,當有時內容並沒有任何變化,但Last-Modified卻改變了,導致文件沒法使用緩存
-
有可能存在服務器沒有准確獲取文件修改時間,或者與代理服務器時間不一致等情形
Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符,能夠更加准確的控制緩存。Last-Modified與ETag是可以一起使用的,服務器會優先驗證ETag,一致的情況下,才會繼續比對Last-Modified,最后才決定是否返回304。
用戶行為緩存
用戶操作 | Expires/Cache-Control | Last-Modified/Etag |
---|---|---|
地址欄回車 | 有效 | 有效 |
頁面鏈接跳轉 | 有效 | 有效 |
新開窗口 | 有效 | 有效 |
前進、后退 | 無效 | 有效 |
Ctrl+F5刷新 | 無效 | 無效 |
HTTP請求流程圖
瀏覽器的第一次請求
瀏覽器再次請求時
附:
Expires
Expires字段聲明了一個網頁或URL地址不再被瀏覽器緩存的時間,一旦超過了這個時間,瀏覽器都應該聯系原始服務器。RFC告訴我們:“由於推斷的失效時間也許會降低語義透明度,應該被謹慎使用,同時我們鼓勵原始服務器盡可能提供確切的失效時間。”
Cache-Control
Cache-Control字段中可以聲明多些元素,例如no-cache, must-revalidate, max-age=0等。這些元素用來指明頁面被緩存最大時限,如何被緩存的,如何被轉換到另一個不同的媒介,以及如何被存放在持久媒介中的。但是任何一個 Cache-Control指令都不能保證隱私性或者數據的安全性。“private”和“no-store”指令可以為隱私性和安全性方面提供一些幫助,但是他們並不能用於替代身份驗證和加密。
Last-Modified
Last-Modified和ETag是條件請求(Conditional Request)相關的兩個字段。如果一個緩存收到了針對一個頁面的請求,它發送一個驗證請求詢問服務器頁面是否已經更改,在HTTP頭里面帶上” ETag”和”If Modify Since”頭。服務器根據這些信息判斷是否有更新信息,如果沒有,就返回HTTP 304(NotModify);如果有更新,返回HTTP 200和更新的頁面內容,並且攜帶新的”ETag”和”LastModified”。
使用這個機制,能夠避免重復發送文件給瀏覽器,不過仍然會產生一個HTTP請求。
ETag
既然有了Last-Modified,為什么還要用ETag字段呢?因為如果在一秒鍾之內對一個文件進行兩次更改,Last-Modified就會不正確。因此,HTTP/1.1利用Entity Tag頭提供了更加嚴格的驗證