協商快取
所謂“協商”,可以理解為:客戶端和服務端雙方商量著來。
客戶端檢查資源超過有效期、強快取命中失敗的情況下,則發出請求“詢問”伺服器是否資源真的過期了,詢問的同時在請求頭要攜帶著資源的「上次更新時間」或者「唯一實體標識」(不同http版本導致的共存問題)。
服務端核對客戶端要請求的資源的「上次更新時間」或者「唯一實體標識」:
若一致,說明命中協商快取,只返回304; 若不一致,說明資源有更新,則返回200、新資源,同時響應頭返回「資源修改時間」後者「資源最新的實體標識」。同時,客戶端拿到新的資源及其修改時間與標識後,重新進行快取。
概括如下圖:
快取驗證
協商快取就是快取驗證。
觸發時機:
使用者點選重新整理按鈕時會開始快取驗證。 如果快取的響應頭資訊裡含有"Cache-control: must-revalidate”的定義,在瀏覽的過程中也會觸發快取驗證。 另外,在瀏覽器偏好設定裡設定Advanced->Cache為強制驗證快取也能達到相同的效果。
觸發條件:
只有在伺服器返回強校驗器或者弱校驗器時才會進行驗證。
附帶條件請求
形如 If-xxx 這種樣式的請求首部欄位,都可稱為條件請求。
伺服器接 收到附帶條件的請求後,只有判斷指定條件為真時,才會執行請求。
協商快取中,就有很多這樣的附帶條件請求。
《圖解HTTP》
協商快取 特點:
服務端校驗 304 Not Modified狀態碼 Last-Modified Etag
304(Not Modified)
該狀態碼雖然是3XX的類別,但是跟301、302不一樣,不是重定向的含義。
304,Not Modified。表示服務端資源未改變,可直接使用客戶端快取過的、未過期的資源。
他的觸發條件是:
1、客戶端採用GET方法,且在請求報文中含有“If-Match”、“If-Modified-Since”、“If-None-Match”、“If-Range”、“If-Unmodified-Since”等欄位
2、伺服器端接收到請求,允許請求並訪問資源。但因客戶端的請求未滿足條件,就直接返回了304。
304狀態碼返回時,不包含任何響應的主體部分。
也就是說,如果命中協商快取,服務端響應請求時,只會返回一個304狀態碼、並沒有實際上的檔案內容,因此在響應體體積上的節省是協商快取的優化點
HTTP/1.0 Last-Modified組
Last-Modified (資源的最後修改日期時間)
實體首部欄位:Last-Modified,表示資源最後被修改的時間。
格式如:
last-modified: Thu, 01 Jan 1970 00:00:00 GMT
這句話就像是伺服器告訴客戶端,你請求的這個檔案是1970年1月1日修改的。
Last-Modified是一種快取弱校驗器。說它弱是因為它只能精確到一秒。
如果響應頭裡含有這個資訊,客戶端可以在後續的請求中帶上 If-Modified-Since 來驗證快取:
If-Modified-Since (比較資源的更新時間)
請求首部欄位
他是與Last-Modified對應的欄位,儲存的是上次快取的資源最終更新時間,也就是上次快取資源時獲取的Last-Modified的值。
用於確認代理伺服器/客戶端擁有的本地資源的有效性。
如果在If-Modified-Since欄位指定的日期時間後,資源發生了改變,伺服器會接受請求。
上圖中,服務端拿著他的值和服務端本地被請求資源的Last-Modified進行比較:
如果Last-Modified <= If-Modified-Since,說明資源一致,命中協商快取,返回304狀態碼 Not Modified即可。 如果Last-Modified > If-Modified-Since,說明資源被修改,需要返回最新資源給客戶端。
他的格式如:
if-modified-since: Thu, 01 Jan 1970 00:00:00 GMT
HTTP/1.1 Etag組
Etag (資源的匹配資訊)
響應首部欄位,快取的一種強校驗器。
實體標記(Etag)是與特定資源關聯的特定值,是資源唯一性標識的字串。伺服器會為每份資源分配對應的 ETag 值。 並通過響應頭首部欄位告知客戶端資源的實體標識。
格式如:
etag: f7b80870fbcd8f9da18ab22d2ef1932c
特點:
當資源更新時,ETag 值也需要更新。 而且,生成 ETag 值時,並沒有統一的演算法規則,而僅僅是由伺服器來分配。所以分散式伺服器系統,一模一樣的一個檔案的Etag值可能不一樣。 此外,因為是按照內容不同來生成的唯一標識,中英文對應版本的資源,雖然地址相同,其Etag不同。
強弱Etag:
ETag 中有強 ETag 值和弱 ETag 值之分。
強ETag值
強 ETag 值,不論實體發生多麼細微的變化都會改變其值。
ETag: "usagi-1234"
弱ETag值
弱 ETag 值只用於提示資源是否相同。只有資源發生了根本改變,產 生差異時才會改變 ETag 值。
這時,會在欄位值最開始處附加 “W/”。如下:
ETag: W/"usagi-1234"
If-None-Match (比較實體標記)
請求首部欄位
他是與Etag對應的欄位,儲存的是上次快取的資源的實體標記值,也就是上次快取資源時獲取的Etag的值。
協商快取時,客戶端攜帶該欄位與服務端資源的Etag欄位值進行比對,只有在If-None-Match的欄位值與Etag值匹配不上、不一致時,命中協商快取。
在GET或HEAD請求方法中,使用If-None-Match可獲取最新的資源。
格式如:
if-none-match: f7b80870fbcd8f9da18ab22d2ef1932c
他和If-Match的作用相反。
If-Match 與412 狀態碼
用法和規則基本同If-None-Match,但判斷邏輯完全相反。
If-Match的這個條件的判斷邏輯是:只有當 If-Match 的欄位值跟 ETag 值匹配一致時才會命中協商快取。伺服器才會接受請求 並返回200和新資料。
反之,伺服器返回狀態碼 412 Precondition Failed 的響應。
還可以使用 星號(*) 指定 If-Match 的欄位值。
針對這種情況,伺服器將會忽略 ETag 的值,只要資源存在就處理請求。
if-match: f7b80870fbcd8f9da18ab22d2ef1932c
或者
if-match: *
對比
首先,Etag的優先順序高於Last-Modified。
Last-Modified和Etag的優缺點分析如下:
Last-Modified優點
不存在版本問題,每次請求都會去伺服器進行校驗。伺服器對比最後修改的時間,如果相同返回 304,不同的話返回 200 以及相應的資料資源
Last-Modified缺點
只要資源修改,無論內容是否發生實質性的變化,都會將該資源返回給客戶端。 例如週期性重寫,這種情況下該資源包含的資料實際上是一樣的; 以時刻作為標識,無法識別一秒內進行多次修改的情況。如果資源更新的速度是秒以下單位,那麼該快取是不能被使用的,因為它的時間單位最低是秒; 某些伺服器不能精確的得到檔案最後修改時間; 如果檔案是通過伺服器動態生成的,那麼該方法的更新時間永遠是生成的時間,儘管檔案可能沒有變化,所以起不到快取的作用
Etag優點
可以更加精確的判斷資源是否被修改, 可以識別一秒內多次修改的情況; 不存在版本問題,每次請求時都會去伺服器進行校驗。
Etag缺點
計算 Etag 值需要效能損耗; 分散式伺服器時依賴演算法:分散式伺服器儲存的情況下,計算 Etag 的演算法如果不一樣,會導致瀏覽器從一臺伺服器上獲得頁面內容後到另外一臺伺服器上進行驗證時現 Etag 不匹配的情況。
兩組欄位流程整理如下
最後再整體回顧、複習一下子。
(注意:實際HTTP1.1的請求中,兩組欄位同時包含在請求及響應頭中,我這裡為了加深組CP的印象,分開闡述)
1、Last-Modified組整體流程如下:
伺服器通過 Last-Modified 欄位告知客戶端,資源最後一次被修改的時間 瀏覽器將這個值和內容一起記錄在快取資料庫中 下一次請求相同資源的時候,瀏覽器從自己的快取中找出"不確定是否過期的"快取。因此在請求頭中將上次的 Last-Modified 的值寫入到請求頭的 If-Modified-since 欄位 伺服器會將 If-Modified-since 的值與 If-Modified 欄位進行對比。如果相等,則表示未修改,響應 304;反之,表示修改響應 200 狀態碼並返回資料
2、Etag組整體流程如下:
瀏覽器在發起請求時,伺服器在響應頭中返回請求資源的唯一標識。在下一次請求時,會將上一次返回的 Etag 值賦值給 If-None-match 並新增在響應頭中。伺服器將瀏覽器傳來的 if-no-matched 跟自己的本地的資源的 Etag 做對比,如果匹配,則返回 304 通知瀏覽器讀取本地快取,否則返回 200 和更新後的資源。