當我們在談論HTTP快取時我們在談論什麼

OBKoro1發表於2018-06-11

在瀏覽器眾多快取中的HTTP快取可能很多人對這個的概念並沒有很清晰,每個人都知道進入一次網頁之後再重新整理一次頁面,載入速度會比首次載入快非常多,每個人都知道這是瀏覽器快取的magic,但是對此背後的原因可能不甚瞭解...

當我們在談論HTTP快取時我們在談論什麼:

我們實際上是在談論下面這兩種情況:

當我們在談論HTTP快取時我們在談論什麼

如上圖,瀏覽器對靜態資源的HTTP快取有兩種情況,一種是強快取(本地快取),另一種是弱快取(協商快取)。


快取流程:

瀏覽器第一次請求資源時:

圖片出自網路

瀏覽器第一次請求資源時,必須下載所有的資源,然後根據響應的header內容來決定,如何快取資源。可能採用的是強快取,也可能是弱快取

瀏覽器後續請求資源時的匹配流程:

當我們在談論HTTP快取時我們在談論什麼

由上圖可以知道當瀏覽器請求一個靜態資源時的HTTP流程:

  1. 強快取階段:先在本地查詢該資源,如果發現該資源,並且其他限制也沒有問題(比如:快取有效時間),就命中強快取,返回200,直接使用強快取,並且不會傳送請求到伺服器
  2. 弱快取階段:在本地快取中找到該資源,傳送一個http請求到伺服器,伺服器判斷這個資源沒有被改動過,則返回304,讓瀏覽器使用該資源。
  3. 快取失敗階段(重新請求):當伺服器發現該資源被修改過,或者在本地沒有找到該快取資源,伺服器則返回該資源的資料。

強快取與弱快取的區別:

獲取資源形式: 都是從快取中獲取資源的。

狀態碼: 強快取返回200(from cache),弱快取返回304狀態碼

請求(最大區別)

強快取不傳送請求,直接從快取中取。

弱快取需要傳送一個請求,驗證這個檔案是否可以使用(有沒有被改動過)。


強快取:

強快取是利用Expires或者Cache-Control,讓原始伺服器為檔案設定一個過期時間,在多長時間內可以將這些內容視為最新的。

若時間未過期,則命中強快取,使用快取檔案不傳送請求。

Cache-Control

Cache-Control 是http1.1中為了彌補Expires的缺陷而加入的,當Expires和Cache-Control同時存在時,Cache-Control優先順序高於Expires。

選項

可快取性:

public: 伺服器端和瀏覽器端都能快取

private: 只能瀏覽器端快取

no-cache: 強制瀏覽器在使用cache拷貝之前先提交一個http請求到源伺服器進行確認。http請求沒有減少,會減少一個響應體(檔案內容),這種個選項類似弱快取。

only-if-cached: 表明客戶端只接受已快取的響應,並且不要向原始伺服器檢查是否有更新的拷貝。

到期設定:

max-age=60:設定快取儲存的最大週期,超過這個時間快取被認為過期(單位秒)。 這裡是60秒

其他設定:

no-store: 不快取,使用協商快取

must-revalidate: 快取必須在使用之前驗證舊資源的狀態,並且不可使用過期資源。

更多設定,移動MDN

// 示例
Cache-Control: no-cache, no-store, must-revalidate
Cache-Control:public, max-age=31536000
Cache-Control: max-age=3600, must-revalidate
複製程式碼

http1.0時代的快取 Expires+Pragma

Expires用於設定快取到期時間

指定快取到期GMT的絕對時間,如果設了max-age,max-age就會覆蓋expires,如果expires到期需要重新請求。

Expires:Sat, 09 Jun 2018 08:13:56 GMT
複製程式碼

有一個問題是由於使用具體時間,如果時間表示出錯或者沒有轉換到正確的時區都可能造成快取生命週期出錯。

Pragma禁用快取:

Pragma : no-cache 表示防止客戶端快取,需要強制從伺服器獲取最新的資料;

Pragma : no-cache  //只有這一個用法 禁用快取,強制從伺服器獲取最新的資料; 
複製程式碼

強快取命中 from memory cache & from disk cache

在測試的時候,看到命中強快取時,有兩種狀態,200 (from memory cache) cache & 200 (from disk cache),於是去找了一下這兩者的區別:

memory cache: 將資源存到記憶體中,從記憶體中獲取。

disk cache:將資源快取到磁碟中,從磁碟中獲取。

二者最大的區別在於:當退出程式時,記憶體中的資料會被清空,而磁碟的資料不會

更詳細的介紹推薦這篇文章


弱快取:

如果強快取時間過期,或者沒有設定,導致未命中的話。就進入到了弱快取的階段了,

Last-Modified & if-modified-since:

Last-Modified與If-Modified-Since是一對報文頭,屬於http 1.0。

last-modified是web伺服器認為檔案的最後修改時間,last-modified是第一次請求檔案的時候,伺服器返回的一個屬性。

Last-Modified: Sat, 09 Jun 2018 08:13:56 GMT 
複製程式碼

第二次請求這個檔案時,瀏覽器把If-Modified-Since傳送給伺服器,詢問該時間之後檔案是否被修改過。

If-Modified-Since: Sat, 09 Jun 2018 08:13:56 GMT // 跟Last-Modified的值一樣
複製程式碼

ETag & If-None-Match

ETag與If-None-Match是一對報文,屬於http 1.1。

ETag是一個檔案的唯一標誌符。就像一個雜湊或者指紋,每個檔案都有一個單獨的標誌,只要這個檔案發生了改變,這個標誌就會發生變化。

ETag機制類似於樂觀鎖機制,如果請求報文的ETag與伺服器的不一致,則表示該資源已經被修改過來,需要發最新的內容給瀏覽器。

ETag也是首次請求的時候,伺服器返回的:

ETag: "8F759D4F67D66A7244638AD249675BE2" // 長這樣
複製程式碼

If-None-Match也是瀏覽器傳送到伺服器驗證,檔案是否改變的:

If-None-Match: "8F759D4F67D66A7244638AD249675BE2" // 跟ETag的值一樣
複製程式碼

Etag/lastModified過程如下:

  1. 客戶端第一次向伺服器發起請求,伺服器將附加Last-Modified/ETag到所提供的資源上去
  2. 當再一次請求資源,如果沒有命中強快取,在執行在驗證時,將上次請求時伺服器返回的Last-Modified/ETag一起傳遞給伺服器
  3. 伺服器檢查該Last-Modified或ETag,並判斷出該資源頁面自上次客戶端請求之後還未被修改,返回響應304和一個空的響應體

同時使用兩個報文頭:

同時使用這兩個報文頭,兩個都匹配才會命中弱快取,否則將重新請求資源。

當我們在談論HTTP快取時我們在談論什麼

Etag 主要為了解決 Last-Modified 無法解決的一些問題:

  1. 一些檔案也許內容並不改變(僅僅改變的修改時間),這個時候我們不希望檔案重新載入。(Etag值會觸發快取,Last-Modified不會觸發)
  2. If-Modified-Since能檢查到的粒度是秒級的,當修改非常頻繁時,Last-Modified會觸發快取,而Etag的值不會觸發,重新載入。
  3. 某些伺服器不能精確的得到檔案的最後修改時間。

使用者操作行為與快取

F5重新整理導致強快取失效。

ctrl+F5強制重新整理頁面強快取,弱快取都會失效。

圖片出自網路

如何設定?

一般是伺服器端設定這些請求頭的,我自己試了用阿里雲伺服器設定Cache-Control,設定一下很方便的。


小結

通過網路重複請求資源既緩慢,成本又高,快取和重用以前獲取的資源的能力成為優化效能很關鍵的一個方面,也是大廠面試時很頻繁出現的內容,掌握好這塊知識點是非常重要的,希望本文能給你帶來些收穫。

文章如有不正確的地方歡迎各位路過的大佬鞭策!喜歡的話,趕緊點波訂閱關注/喜歡。

鼓勵我一下:

覺得還不錯的話,給我的專案點個star

相關文章