「MISC」HTTP 緩存控制

如今的Web應用愈來愈複雜,體驗愈來愈好。相應的,資源文件也愈來愈大,若是能讓客戶端在資源沒更新的狀況下,直接取用緩存的數據,那麼不只資源加載的更快,服務器壓力更小,也爲綠色地球作出了一份貢獻。程序員

程序員向來是追求最優,在設法緩存靜態資源之後,你們又找到了一些方法來緩存動態生成的內容。看來程序員們都是環境保護主義者(笑。緩存

從HTTP/1.0-HTTP/1.1,一共產生了3種控制緩存的方法:服務器

  • Expires(響應頭,HTTP/1.0)
  • Cache-Control(響應頭,HTTP/1.1)代理

    - Last-Modified(響應頭),If-Modified-Since(請求頭)
    - Etag(響應頭),If-None-Match(請求頭)

以上就是HTTP控制緩存的方法。code

除了這些,在第二個還有If-Unmodified-Since,第三個還有If-Match。但這兩個響應頭不是爲了控制緩存,而是爲了確認修改的資源的一致性。以後會介紹。資源

HTTP/1.0

Expires

Expires: <http-date>

其中 <http-date> 的格式以下:io

Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
Example: Fri, 03 Nov 2017 03:22:39 GMT

當設置了Expires後,客戶端在此日期以前都不會去請求服務器,而是直接從緩存中取。
不過這樣也有一個問題:若是徹底不去請求服務器的話,在資源過時以前若是資源有更新,客戶端仍是使用着以前的資源。因此就產生了下面更加高級的緩存控制方法(第3、第四項方法)。ast

不過還有一個方法能解決這個問題:將資源的Expires設置爲一個足夠長的時間,而資源名爲資源的Hash值,這樣資源更新了之後,也使用的是不一樣的名稱。那麼就不存在上面的問題了。date

HTTP/1.1

Cache-Control

Expires只能設置具體的日期,這樣的話,若是客戶端與服務器的時間不一致,會致使緩存時間不正確,還有可能直接致使緩存失效。語法

HTTP/1.1的Cache-Control配合If-Modified-Since或If-None-Match則完美的解決了這個問題。

Cache-Control比較經常使用的指令以下:

  • 可緩存性

    • public: 響應可被任意緩存
    • private: 響應只能被客戶端緩存,不能被中間節點(代理、CDN等)緩存
    • no-cache: 中間節點必須向原始服務器去驗證緩存有效性。若是自己是原始服務器,則向本身確認
    • only-if-cached: 中間節點直接使用已存在的緩存來確認有效性,不向原始服務器確認。若自己是原始服務器,則此指令沒有效果。
  • 過時控制

    • max-age=<seconds>: 指定相對於請求時間的過時時間,以秒爲單位。
  • 再驗證

    • must-revalidation: 緩存過時後必須向服務器確認緩存是否有效
  • 其餘

    • no-store: 忽略緩存的存在,直接向服務器請求最新的資源。

上面列表中向服務器確認緩存是否有效的技術手段就是下文介紹的 Last-Modified/If-Modified-SinceETag/If-None-Match

Last-Modified / If-Modified-Since

Last-Modified: <http-date>

Last-Modified頭是服務器告訴客戶端此資源的最後修改時間,客戶端則會將資源和這個時間都儲存起來。以後,根據Cache-Control的指令,若是須要同服務器確認資源的有效性的時候則會將這個時間放在If-Modified-Since頭中,供服務器進行比較,是返回304仍是200。

If-Modified-Since頭只會在GET和HEAD請求被附加進請求頭。

If-Unmodified-Since

If-Unmodified-Since: <http-date>

通常來講在PUT, POST等方法使用,表示該次請求更新的資源的日期爲<http-date>,若是服務器檢測到現存資源的日期不爲<http-date>(即已經被其餘的方式更新了),則會失敗並返回412。

ETag / If-None-Match

ETag: W/"<etag_value>"
ETag: "<etag_value>"
If-None-Match: "<etag_value>"[, "<etag_value>"...]
If-None-Match: W/"<weak_etag_value>"[, "<weak_etag_value>"]

若是將上面的 Last-Modified / If-Modified-Since 應用在動態的數據上的話,基本上沒有可行性。那麼就有了此方式的緩存。

在第一次請求的時候,服務器會附帶ETag頭。ETag的值是根據響應的內容來進行生成的,通常來講是內容(+其餘一些標識的)哈希值。以後,根據Cache-Control的指令,若是須要同服務器確認資源的有效性的時候則會將這個etag_value放在If-None-Match頭中,供服務器進行比較,是返回304仍是200。

在ETag的值前若是有W/則表示這是一個弱Etag。弱ETag相等意味着這兩個內容語義上是相等的,強ETag相等則表示內容每個字節都相等。

舉個弱ETag的例子:返回的數據中帶有log信息,而兩次返回的數據是相同的,log不一樣。

還有一種語法:If-None-Match: *,基本上用在PUT, POST等上,用於上傳。表示要求上傳的文件在服務器上不存在。

If-Match

If-Match: "<etag_value>"[, "<etag_value>"...]
If-Match: W/"<weak_etag_value>"[, "<weak_etag_value>"]

對於GET, HEAD等請求,若是資源的ETag匹配上If-Match的值,則返回資源,不然返回412。
對於PUT, POST等請求,若是現有資源的Etag匹配上If-Match的值,那麼進行寫操做,不然失敗返回412。

----- 記得點贊 -----

相關文章
相關標籤/搜索