HTTP 快取機制
緒論
當web請求到達快取時,如果本地有”已快取”的副本,就可以從本地裝置而不是原始伺服器中提取這個文件
使用快取的好處
- 減少了冗餘的資料傳輸
- 緩解了網路瓶頸的問題
- 降低了對原始伺服器的要求
- 降低了距離時延
應用快取時可能會出現的幾種情況
命中的和未命中的
可用的已有副本為某些到達快取的請求提供服務,這被稱為快取命中。
其他一些到達快取的請求可能會由於沒有副本可用,而被轉發給原始伺服器,這被稱為快取未命中。
快取再驗證命中與快取再驗證未命中
下面問題就來了,如果我們一直使用快取中的文件,如何把伺服器上最新的變動告知客戶端?
HTTP使用了一些簡單的機制,來保持已快取資料與伺服器資料之間的一致性。
通過『新鮮度檢測』(也叫做HTTP再驗證)可以對伺服器上的文件進行檢測,從而檢視當前快取的文件是不是伺服器上的最新版本。
HTTP通過在請求首部新增”If-Modified-Since”欄位,可以實現再驗證的過程。再驗證的結果有以下三種可能:
- 再驗證命中:即快取中的副本與伺服器中的文件依然相同,伺服器返回304 Not Modified,表示伺服器物件未被更改
- 再驗證未命中:即伺服器上的文件發生了變動,伺服器返回完整的200 OK響應,表示伺服器物件已與快取物件不同,重新從伺服器獲取物件
- 物件被刪除:伺服器返回一個404 Not Found響應,表示伺服器上該物件已被刪除
下面對快取機制進行詳細說明
快取機制
過程一
客戶端傳送一個GET請求到快取,並判斷快取中是否存在所請求檔案的副本。
=== 有,則進入 -> 過程五 ===
=== 沒有,則進入 -> 過程二 ===
過程二
當前快取中沒有所請求檔案的副本,則將請求轉發到伺服器。
=== 進入 -> 過程三 ===
過程三
伺服器收到請求,將完整的請求內容包含在響應裡。
通過特殊的HTTPCache-Control首部和Expires首部,HTTP讓伺服器向每個文件附加了一個”過期時間”,並將文件存入快取當中。在文件過期之前,快取可以任意頻率使用這些副本,而無需與伺服器聯絡(除非請求中有限制)。
同時,響應頭還包括Last-Modified首部和Etag首部。這兩個首部表示此時請求的檔案最新一次修改是什麼時候(Last-Modified:< date >)和當前的標籤是什麼(Etag:< tag >)。
=== 進入 -> 過程四 ===
過程四
快取最後將收到的文件提供給客戶端
=== OVER ===
過程五
檢測快取中對應檔案的過期時間,判斷文件是否”新鮮”
=== 新鮮,則進入 -> 過程六 ===
=== 不新鮮,則進入 -> 過程七 ===
過程六
直接將快取中的檔案提供給客戶端
=== OVER ===
過程七
用條件方法進行再驗證:快取向原始伺服器傳送一個”條件GET”
HTTP定義了5個條件請求首部。
- If-Modified-Since
- If-Unmodified-Since
- If-Match
- If-None-Match
- If-Range
其中最有用的是If-Modified-Since和If-None-Match
還記得上文提到的伺服器響應中的Last-Modified首部和Etag首部嗎?在傳送”條件請求的時候”,請求首部中If-Modified-Since的值即為上次在響應中收到的Last-Modified的值,而If-None-Match的值即為上次收到的響應中Etag的值。
舉個例子來說明:
假設”今天”是 2017年3月20日,在這一天,伺服器上A檔案最後的更新日期為 2017年3月18日 00:00。客戶端在”今天”向伺服器請求A檔案,服務端返回內容的同時,在響應頭添加了Last-Modified: 2017年3月18日 00:00(注:真正的日期格式應該是這種:Tue, 10 Jan 2017 16:05:44 GMT,這裡為了方便進行了簡寫),客戶端收到響應之後表示已經知道這個檔案在服務端的最後更改日期是哪天了。下次客戶端再發送條件請求的時候,就將If-Modified—Since設定為之前收到的Last-Modified首部的值。通過這種方式就能夠檢測距離上次請求到現在這一刻位置,所請求物件是否發生改變。
Etag和If-None-Match的使用方法也類似上述過程。
=== 進入 -> 過程八 ===
過程八
伺服器將接收到的請求頭中的If-Modified-Since和If-None-Match首部的值取出,並與伺服器上對應請求的文件資訊進行對比
=== 條件為真,則表示檔案已發生變動,進入 -> 過程十一 ===
=== 條件為假,則表示檔案沒有變化,進入 -> 過程九 ===
過程九
服務端返回 304 Not Modified,並且在響應頭中加入新的Cache-Control和/或Expires首部,用來更新快取上的”新鮮度資訊”。
=== 進入 -> 過程十 ===
過程十
將快取中的檔案提供給客戶端
=== OVER ===
過程十一
向服務端請求更新後的檔案
=== 進入 -> 過程三 ===
其他
Cache-Control
該首部可以設定的值:
max-age=XXXX(設定相對秒數,即還有XXXX秒檔案變為”不新鮮”)
s-maxage=XXXX(僅適用於共有快取)
no-store(禁止快取對響應進行復制)
no-cache(響應可以存在快取中,但是每次都要進行再驗證)
Expires 和 Cache-Control
Expirese使用絕對日期,但由於許多伺服器時鐘都不同步,因此不建議使用
而Cache-Control則使用相對時間
If-Modified-Since 和 If-None-Match
當請求中同時存在If-Modified-Since 和 If-None-Match兩種首部,則只有當兩者條件都為真的時候,伺服器才返回304 Not Modified