[前端 · 面試 ]HTTP 總結(九)—— HTTP 協商快取

程式設計三昧發表於2021-08-10

最近我在做前端面試題總結系列,感興趣的朋友可以新增關注,歡迎指正、交流。

爭取每個知識點能夠多總結一些,至少要做到在面試時,針對每個知識點都可以侃起來,不至於啞火。

前言

通過前面的介紹,我們知道 HTTP 快取分為兩種:

  • 強快取
  • 協商快取

HTTP 快取分類

在上一篇文章中,我們瞭解了 HTTP 強快取,今天我們來了解一下協商快取相關的內容。

協商快取

特點

協商快取,也稱為對比快取,從名稱可以看出,它沒有強制快取那麼霸道,可以有商有量的來確定是否使用快取資源。

協商快取機制下,瀏覽器需要傳送快取標識,去向伺服器驗證快取標識是否有效,進而判斷是重新發起請求、下載完整的響應,還是從本地獲取快取的資源。

如果服務端提示快取資源未改動(Not Modified),資源會被重定向到瀏覽器快取,這種情況下網路請求對應的狀態碼是 304,比如:

image-20210809205941306

規則

協商快取的整體規則如下所示:

image-20210809211515291

從上圖可以看出,雖然客戶端仍然發起了 HTTP 請求伺服器,但是伺服器只做了標誌對比來確認是否使用快取,如果確認使用快取,就不會再返回具體的資源了。這樣做雖然沒有減少請求數量,但是極大減小了請求負荷,可以明顯提升請求速度和減小網路頻寬。

上圖是快取標識正常有效的時序圖,但其實協商快取的驗證結果也存在兩種情況:

  • 標識有效
  • 標識過期

協商快取需要配合強快取使用,使用協商快取需要先設定 Cache-Control:no-cache 或者 pragma:no-cache 來告訴瀏覽器不走強快取。

標識過期

image-20210809211805478

屬性

對於協商快取來說,快取標識的傳遞是我們著重需要理解的,它在 Response Header 和 Request Header 之間進行傳遞。

快取標識可以分為兩類:

  • Last-Modified 和 If-Modified-Since
  • Etag 和 If-None-Match

我們一般會說,協商快取的快取標識是 Last-Modified(最後修改時間) 和 Etag(標籤或名稱),因為它們兩個都是由服務端確定並返回的。

瀏覽器攜帶的是具有判斷意味的屬性 —— If-Modified-Since(從什麼時間以來是否改變) 和 If-None-Match(是否匹配不到)。

快取標識的攜帶位置如下圖所示:

image-20210810115518959

在具體的網路請求中,快取標識如下圖所示:

image-20210810141436762

Last-Modified 和 If-Modified-Since

Last-Modified 和 If-Modified-Since 是 HTTP 1.0 引入的。

Last-Modified

當瀏覽器第一次訪問一個資源的時候,伺服器會在 Response 、Header 中返回一個 Last-Modified,代表這個資源最後的修改時間。

If-Modified-Since

再次請求伺服器時,請求頭會攜帶此欄位,值為上次請求時伺服器返回的 Last-Modified 的值。

伺服器收到請求後發現有頭 If-Modified-Since 則與被請求資源的最後修改時間進行比對:

  • 若資源的最後修改時間大於 If-Modified-Since,說明資源又被改動過,則響應整片資源內容,返回狀態碼 200 和最新的資源,響應頭中攜帶最新的快取標識 Last-Modified。
  • 若資源的最後修改時間小於或等於 If-Modified-Since,說明資源無新修改,則響應 HTTP 304,告知瀏覽器繼續使用所儲存的 cache。

缺陷

使用 Last-Modified 是有一定缺陷的:

  • 如果資源更新的速度是秒以下單位,那麼該快取是不能被使用的,因為 If-Modified-Since 只能檢查到以秒為最小計量單位的時間差。
  • 如果檔案是通過伺服器動態生成的,那麼該方法的更新時間永遠是生成的時間,儘管檔案可能沒有變化,所以起不到快取的作用。
  • 我們編輯了檔案,但檔案的內容沒有改變。服務端並不清楚我們是否真正改變了檔案,它仍然通過最後編輯時間進行判斷。因此這個資源在再次被請求時,會被當做新資源,進而引發一次完整的響應——不該重新請求的時候,也會重新請求。

為了解決上面伺服器沒有正確感知檔案變化的問題,Etag 作為 Last-Modified 的補充出現了。

Etag 和 If-None-Match

Etag 和 If-None-Match 是一對報文頭,屬於HTTP 1.1。

ETag 和 If-None-Match 的值是一串 hash 碼,代表的是一個資源的識別符號,當服務端的檔案變化的時候,它的 hash 碼會隨之改變。

Etag

伺服器響應請求時,告訴瀏覽器當前資源在伺服器的唯一標識(生成規則由伺服器決定)。

ETag 又有強弱校驗之分,如果 hash 碼是以 “W/“ 開頭的一串字串,說明此時協商快取的校驗是弱校驗的,只有伺服器上的檔案差異(根據 ETag 計算方式來決定)達到能夠觸發 hash 值字尾變化的時候,才會真正地請求資源,否則返回 304 並載入瀏覽器快取。

If-None-Match

再次請求伺服器時,通過此欄位通知伺服器客戶段快取資料的唯一標識。

伺服器收到請求後發現有頭 If-None-Match 則與被請求資源的唯一標識進行比對:

  • 不同,說明資源又被改動過,則響應整片資源內容,返回狀態碼 200。
  • 相同,說明資源無新修改,則響應 HTTP 304,告知瀏覽器繼續使用所儲存的 cache。

缺陷

Etag 的生成過程需要伺服器額外付出開銷,會影響服務端的效能,這是它的弊端。

因此啟用 Etag 需要我們審時度勢:

  • Etag 並不能替代 Last-Modified,它只能作為 Last-Modified 的補充和強化存在。
  • Etag 在感知檔案變化上比 Last-Modified 更加準確,優先順序也更高。
  • 當 Etag 和 Last-Modified 同時存在時,以 Etag 為準。

兩種屬性比較

  • 在精確度上,Etag 要優於 Last-Modified,Last-Modified 的時間單位是秒,如果某個檔案在 1 秒內改變了多次,那麼他們的 Last-Modified 其實並沒有體現出來修改,但是 Etag 每次都會改變確保了精度。
  • 在效能上,Etag 要遜於 Last-Modified,畢竟 Last-Modified 只需要記錄時間,而 Etag 需要伺服器通過演算法來計算出一個 hash 值。
    在優先順序上,伺服器校驗優先考慮 Etag。

總結

總結一下上面的內容:

  • 協商快取是依靠快取標識來判斷資源是否有效。
  • 快取標識包括 Last-Modified(If-Modified-Since)和 Etag(If-None-Match)。
  • 響應頭攜帶的是 Last-Modified 和 Etag。
  • 請求頭攜帶的是 If-Modified-Since 和 If-None-Match。
  • Etag 是 Last-Modified 的補充和完善,並不能完全替代 Last-Modified。
  • Etag 的優先順序高於 Last-Modified。
  • Last-Modified 的效能要高於 Etag,但是精確性卻遜色於 Etag。

以上就是 HTTP 協商快取的相關內容。

~

~本文完,感謝閱讀!

~

學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!

大家好,我是〖程式設計三昧〗的作者 隱逸王,我的公眾號是『程式設計三昧』,歡迎關注,希望大家多多指教!

你來,懷揣期望,我有墨香相迎! 你歸,無論得失,唯以餘韻相贈!

知識與技能並重,內力和外功兼修,理論和實踐兩手都要抓、兩手都要硬!

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章