有關 HTTP 快取的首部欄位說一下

amadan發表於2021-09-09

常見的HTTP 快取首部欄位有:

  • Expires:響應頭,代表該資源的過期時間

  • Cache-Control:請求/響應頭,快取控制欄位,精確控制快取策略

  • If-Modified-Since:請求頭,資源最近修改時間,由瀏覽器告訴伺服器

  • Last-Modified:響應頭,資源最近修改時間,由伺服器告訴瀏覽器

  • Etag:響應頭,資源標識,由伺服器告訴瀏覽器

  • If-None-Match:請求頭,快取資源標識,由瀏覽器告訴伺服器

其中, 強快取

  • Expires(HTTP/1.0)
  • Cache-Control(HTTP/1.1)

協商快取:

  • Last-Modified 和 If-Modified-Since(HTTP/1.0)
  • ETag 和 If-None-Match(HTTP/1.1)

快取過程分析

瀏覽器與伺服器通訊的方式為應答模式,即瀏覽器發起 HTTP 請求,伺服器響應請求。在瀏覽器第一次發起請求時,會根據響應報文中 HTTP 頭的快取標識,決定是否快取結果,如果是則將請求結果和快取標識存入瀏覽器快取中,簡單的過程如下圖:

圖片描述

由上圖我們可以知道:

  • 瀏覽器每次發起請求,都會先在瀏覽器快取中查詢該請求的結果以及快取標識
  • 瀏覽器每次從伺服器端拿到返回的請求結果,都會將該結果和快取標識存入瀏覽器快取中

以上兩點結論就是瀏覽器快取機制的關鍵,它確保了每個請求的快取存入與讀取,只要我們再理解瀏覽器快取的使用規則,那麼所有的問題就迎刃而解了

本文也將圍繞著這點進行詳細分析。為了方便大家理解,這裡我們根據是否需要向伺服器重新發起HTTP請求將快取過程分為兩個部分,分別是:

  • 強快取: 向瀏覽器快取查詢該請求結果,並根據該結果的快取規則來決定是否使用該快取結果的過程
  • 協商快取: 強快取失效後,瀏覽器攜帶快取標識向伺服器發起請求,由伺服器根據快取標識決定是否使用快取的過程

強快取(快取控制)

強快取表示在快取期間是否使用快取(快取是否有效),需不需要重新傳送HTTP請求

圖片描述

控制強快取的欄位分別是 ExpiresCache-Control ,其中 Cache-Control 優先順序比 Expires

Expires(HTTP/1.0)

值為伺服器返回該請求結果快取的到期時間:

Expires: Wed, 22 Oct 2018 08:41:00 GMT

表示資源會在 Wed, 22 Oct 2018 08:41:00 GMT 後過期,需要再次請求。

並且 Expires 受限於客戶端時間,如果修改了客戶端時間,可能會造成快取失效。

所以現在 HTTP/1.1中新增了 Cache-Control

Cache-Control(HTTP/1.1)

Cache-control: max-age=30

該屬性值表示資源會在 30 秒後過期,需要再次請求。也就是說在 30 秒內如果再次發起該請求,則會直接使用快取,強快取生效。

它與 Expires 相比:

  • HTTP響應報文中 Expires 的時間值,是一個絕對值
  • HTTP響應報文中 Cache-Control為max-age=600 ,是相對值(解決 Expires 受限於客戶端時間)

除了 max-age ,它還有以下取值:

圖片描述

注意下面的 no-cache ,資源依然會被快取,並且這個快取要伺服器驗證後才可以使用

圖片描述

max-age=0 和 no-cache 等價嗎?

從規範的字面意思來說,max-age 到期是 應該(SHOULD) 重新驗證,而 no-cache 是 必須(MUST) 重新驗證。但實際情況以瀏覽器實現為準,大部分情況他們倆的行為還是一致的。(如果是 max-age=0, must-revalidate 就和 no-cache 等價了)

總結

自從 HTTP/1.1 開始,Expires 逐漸被 Cache-Control 取代。Cache-Control 是一個相對時間,即使客戶端時間發生改變,相對時間也不會隨之改變,這樣可以保持伺服器和客戶端的時間一致性。而且 Cache-Control 的可配置性比較強大。

Cache-Control 的優先順序高於 Expires,為了相容 HTTP/1.0 和 HTTP/1.1,實際專案中兩個欄位我們都會設定。

協商快取(快取校驗)

如果快取過期了:

  • 沒有 Cache-Control 和 Expires
  • Cache-Control 和 Expires 過期
  • 設定了 no-cache

需要發起請求驗證伺服器資源是否有更新:

  • 有更新,返回200,更新快取
  • 無更新,返回304,更新瀏覽器快取有效期

圖片描述

Last-Modified 和 If-Modified-Since(HTTP/1.0)

  • Last-Modified(響應頭)
  • If-Modified-Since(請求頭)

圖片描述

Last-Modified 表示本地檔案最後修改日期,If-Modified-Since 會將 Last-Modified 的值傳送給伺服器,詢問伺服器在該日期後資源是否有更新,有更新的話就會將新的資源傳送回來,否則返回 304 狀態碼。

但是這種方式存在著一些缺點,例如:

  • 負載均衡的伺服器,各個伺服器生成的 Last-Modified 可能有所不同
  • GMT 格式有最小單位,例如,如果在一秒內有更改將不能被識別

ETag 和 If-None-Match(HTTP/1.1)

為了解決上面的那個問題, HTTP/1.1 加了這組標記

  • ETag(響應頭)
  • If-None-Match(請求頭)

ETag 類似於檔案指紋,是檔案的一個唯一標識序列,當資源有變化時,Etag就會重新生成,If-None-Match 會將當前 ETag 傳送給伺服器,詢問該資源 ETag 是否變動,有變動的話就將新的資源傳送回來。並且 ETag 優先順序比 Last-Modified 高

使用 ETag 就可以精確地識別資源的變動情況,就算是秒內的更新,也會讓瀏覽器感知,能夠更有效地利用快取

ETag 強弱之分

ETag 機制同時支援強校驗和弱校驗。它們透過ETag識別符號的開頭是否存在“W/”來區分,如:

"123456789"   -- 一個強ETag驗證符
W/"123456789"  -- 一個弱ETag驗證符

強 ETag 要求資源在位元組級別必須完全相符,弱 ETag 在值前有個“W/”標記,只要求資源在語義上沒有變化,但內部可能會有部分發生了改變(例如 HTML 裡的標籤順序調整,或者多了幾個空格)

Vary 響應

伺服器透過指定 Vary: Accept-Encoding ,告知代理伺服器,對於這個資源,需要快取兩個版本:

  • 壓縮

  • 未壓縮

這樣老式瀏覽器和新的瀏覽器, 透過代理, 就分別拿到了未壓縮和壓縮版本的資源,避免了都拿同一個資源的尷尬。

Vary: Accept-Encoding, User-Agent

圖片描述

如上設定,代理伺服器將針對是否壓縮和瀏覽器型別兩個維度去快取資源。如此一來,同一個url,就能針對 PC 和 Mobile 返回不同的快取內容。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2310/viewspace-2797373/,如需轉載,請註明出處,否則將追究法律責任。

相關文章