本文知識結構:
今天二毛下了個晚班,坐在異鄉寥寥無幾人的地鐵上,一種“他鄉安置不了靈魂,故鄉放置不了肉身”的感覺襲來,心情有些許低落。
他似玩非玩著手機,突然被幾條資訊吸引了注意力:“熱乾麵回來了”、“全國絕大部分省宣佈開學了”…
二毛突然心情釋懷,想起一句話:冬天已經過去,春天還會遠嗎?一切都在慢慢變好,包括自己。
回到出租屋,二毛突然看到二丫一臉生氣的樣子經過,於是湊上前去關心慰問。
1 HTTP協議的組成部分
開始之前,首先我們需要大概瞭解下 HTTP 協議傳輸資訊的兩個組成部分:請求和響應。
1.1 請求
分為:請求行,請求頭,請求體。
當客戶端向服務端發起請求時,內容層次如下:
其中請求體是伺服器真正要接收處理的使用者資料;請求行和請求頭的一些引數值,主要是用於告訴伺服器如何處理這次請求,比如:
根據content-length的值,伺服器就知道請求體的長度
根據host的值,伺服器就知道要將請求轉發給哪個虛擬主機
……
1.2 響應
分為:響應行,響應頭,響應體。
當服務端響應資源給客戶端時,內容類別如下:
其中響應體是真正展示給使用者的內容(一般是html,交給瀏覽器渲染);響應行和響應頭的一些引數值,主要告訴瀏覽器如何展示響應體的內容,比如:
根據content-type的值,瀏覽器就知道是將這些內容按圖片格式展示,還是以文字方式形式
根據content-length的值,瀏覽器就知道響應內容的長度
……
1.3 快取相關的引數
我們主要挑快取相關的引數來講:狀態碼,頭部欄位。
1.3.1 狀態碼
這裡指的就是服務端的響應狀態碼,狀態碼主要分為以下五種:
其中,重要的快取相關狀態碼如下:
200 OK: 代表資源被瀏覽器成功接收,或資源直接從本地獲取成功。
304 Not Modified:代表服務端允許請求訪問資源,但訪問資源未滿足條件,不需要將資源響應返回給客戶端。
1.3.2 頭部欄位
認真閱讀的朋友們可能會發覺到,上面請求頭和響應頭的引數怎麼有些是一樣的(上文的content-type)。的確,其實請求頭和響應頭都叫做頭部欄位。頭部欄位分為以下四種:
1 請求首部欄位(Request Header Fields)
從客戶端向伺服器端傳送請求報文時使用的首部。
2 響應首部欄位(Response Header Fields)
從伺服器端向客戶端返回響應報文時使用的首部。
3 通用首部欄位(General Header Fields)
請求報文和響應報文兩方都會使用的首部。
4 實體首部欄位(Entity Header Fields)
針對請求報文和響應報文的實體部分使用的首部。補充了資源內容更新時間等與實體有關的資訊。
關於快取,我們需要關注這幾種頭部資訊:
請求相關:If-Modified-Since,If-None-Match
響應相關:ETag,Last-Modified,Expires,Cache-Control
2 瀏覽器快取型別
正如我前面說到的,瀏覽器快取有兩種,分別是:強快取和協商快取。
2.1 強快取
定義:
顧名思義,就是瀏覽器強制使用本地快取來作為資源展示。
在谷歌瀏覽器按 F12 之後的 network 選項中可以看出:命中強快取的請求,會得到200狀態碼,由於欄位是從本地獲取的,所以size 欄位處會顯示 from memory cache 或 from disk cache。
強快取相關的頭部資訊:
看響應頭部欄位:Expires 和 Cache-Control。
Expires: 例如【expires: Sun, 03 May 2020 15:02:48 GMT】,標明瞭這個資源的過期時間,瀏覽器下一次請求時會對這個時間進行判斷,如果沒超過這個時間就會命中強快取,超過了則沒命中並重新發起請求。
Cache-Control: 例如【cache-control: max-age=2592000】,標明瞭這個資源的過期倒數計時,這個倒數計時瀏覽器也會儲存下來,瀏覽器下一次請求時會對倒數計時進行判斷,如果倒數計時未完就會命中強快取,超過了則反之。
2.2 協商快取
定義
顧名思義,就是要跟伺服器進行協商要不要用快取。
在谷歌瀏覽器按 F12 之後的 network 選項中可以看出:命中協商快取的請求,會得到304狀態碼,然後瀏覽器就會從本地快取中讀取資源。
協商快取相關的頭部資訊
既然是協商,所以此類的頭部資訊是成雙成對出現的:
請求頭的 ETag 與 響應頭的 If-None-Match
請求頭的 Last-Modified 與 響應頭的If-Modified-Since
ETag和If-None-Match:
Etag是上一次載入資源時,伺服器返回的響應頭,是對該資源的一種唯一標識,只要資源有變化,Etag就會重新生成。瀏覽器在下一次載入資源向伺服器傳送請求時,會將上一次返回的Etag值放到請求頭裡的If-None-Match欄位裡,伺服器接受到If-None-Match的值後,會拿來跟該資原始檔的Etag值做比較,如果相同,則表示資原始檔沒有發生改變,命中協商快取。
Last-Modified和If-Modified-Since:
Last-Modified是該資原始檔最後一次更改時間,伺服器會在響應頭裡返回,同時瀏覽器會將這個值儲存起來,在下一次傳送請求時,放到請求頭裡的If-Modified-Since裡,伺服器在接收到後也會做比對,如果相同則命中協商快取。
舉個例子。
響應頭:
請求頭:
ETag和Last-Modified的作用和用法也是差不多,說一說他們的區別。
1 在精確度上,Etag要優於Last-Modified。Last-Modified的時間單位是秒,如果某個檔案在1秒內改變了多次,那麼他們的Last-Modified其實並沒有體現出來修改,但是Etag每次都會改變確保了精度;如果是負載均衡的伺服器,各個伺服器生成的Last-Modified也有可能不一致。
2 在效能上,Etag要遜於Last-Modified,畢竟Last-Modified只需要記錄時間,而Etag需要伺服器通過演算法來計算出一個hash值。
3 在優先順序上,伺服器校驗優先考慮Etag。
3 瀏覽器快取過程示意圖
注意:
兩者的共同點是,都是從客戶端快取中讀取資源;區別是強快取不會發請求,協商快取會發請求。
關於優先順序:先判斷強快取,後判斷協商快取。
判斷強快取的時候,如果有 Cache-Control ,則只通過 Cache-Control 來判斷是否有強快取;如果沒有這個 Cache-Control 這個欄位,** 才拿 ** Expire 欄位進行判斷。
判斷協商快取的時候,如果有 If-None-Match ,則只通過If-None-Match 來判斷是否有協商快取;如果沒有 If-None-Match 這個欄位,** 才拿 ** If-Modified-Since。
https 也是同樣的快取原理,因為 https 只是在 http 的基礎上套了SSL/TLS的加密層,其他不變。
4 針對快取的一些使用者操作
位址列訪問,連結跳轉是正常使用者行為,將會觸發瀏覽器快取機制;
F5重新整理,瀏覽器會設定max-age=0,跳過強快取判斷,會進行協商快取判斷;
ctrl+F5重新整理,跳過強快取和協商快取,直接從伺服器拉取資源。
二丫隨即拿出筆記本按了下 ctrl+F5 ,果不其然,網站系統正常更新了圖片。
我是二毛,一個在大城市漂泊的程式猿。
我的故事未完待續……
關注公眾號《程式設計師二毛》,後臺回覆 1024 領取變強祕籍;
本作品採用《CC 協議》,轉載必須註明作者和本文連結