真正“搞”懂HTTP協議12之快取代理

Zaking發表於2023-02-09

  我們在前兩篇的內容中分別學習了快取和代理,大致瞭解了快取有哪些頭欄位,代理是如何服務於伺服器和客戶端的,那麼把兩者結合起來,代理快取,也就是說代理伺服器也可以快取,當客戶端請求資料的時候,未必一定要追溯到源伺服器上,代理伺服器就可以直接把快取的資料返回給客戶端。並且,HTTP的快取,大多數其實都是由代理伺服器來實現,雖然源伺服器也有各種快取,比如大家可能聽過的Redis,還有Memcache、Varnish等等,但是基本上跟HTTP沒啥關係。

  如果沒有代理快取,代理伺服器僅僅只是一箇中專作用,轉發客戶端和伺服器的豹紋,中間不會儲存任何資料。但是一旦給代理加上快取後,事情就有些變化了。它在轉發報文的同時,還要把報文存入自己的Cache裡。下一次再有同樣的請求,代理伺服器就可以自己決斷,從自己的快取中取出資料返回給客戶端,就無需再去源伺服器獲取。這樣就降低了使用者的等待時間,同時也節約了源伺服器的網路頻寬。

  在HTTP的快取體系中,快取代理的身份十分特殊,它既是客戶端,又是伺服器,同時呢,它也既不是客戶端,又不是伺服器。因為代理面向客戶端,就是伺服器,面向伺服器就表現為客戶端,但是實際上代理又只是箇中轉,並不是真正的資料消費者和生產者,所以我們需要學一些新的Cache-Control屬性來對它做些額外的約束。

  嗯,這些新的屬性就是本篇的重點了。建議大家對比著快取那篇文章來看~

一、源伺服器的快取控制

  源伺服器的快取控制,額……原諒我重複了一遍標題,在有代理伺服器的場景下,它控制了哪些裝置或者說終端或者說客戶端呢?首先源伺服器鏈路前的所有裝置,包括代理伺服器,對於源伺服器來說都是客戶端。那麼問題來了,當有多個同樣角色的時候,我們要怎麼區分它們,針對不同的角色,設定不同的頭欄位屬性呢?

  我們在快取那一章所學的Cache-Control的四個屬性,對於代理伺服器來說也是可以使用的,但是客戶端和代理伺服器肯定是不一樣的,客戶端只是自己使用,但是代理伺服器,可能會分發給很多客戶端使用。所以,第一,我們要做的就是對代理伺服器和源伺服器的HTTP資料做不同的標識。

  首先,我們可以使用“private”和“public”來區分代理伺服器和客戶端上的快取。比如像cookie這種私有性很強的資料,只能儲存在客戶端,不然被黑進了代理獲取了使用者的私有資料那可是很嚴重的問題了。

  還有相對於“must-revalidate”是隻要快取過期,就要去源伺服器驗證,而“proxy-revalidate”只要求代理的快取過期後必須驗證,不必回溯到源伺服器,只驗證代理的快取就可以了。

  再次,快取的生存時間可以使用“s-maxage”,其實就是share-maxage的簡寫,用它來限定在代理上能夠存活多久,而客戶端扔就使用“max-age”。

  還有一個代理專用的屬性,“no-transform”。代理有的時候會對快取下來的資料做一些最佳化,比如把圖片生成如png、webp等各種格式,方便今後的請求,而“no-transform”就會禁止這樣的轉換。

  最後,大家一定要注意,源伺服器在設定完Cache-Control欄位後,必須要為報文加上“Last-Modified”或者“ETag”屬性,否則客戶端和代理後面就無法使用條件請求來驗證快取是否有效。

  最後的最後我們基於快取那一章的流程圖,把代理伺服器的驗證邏輯也加進去。

真正“搞”懂HTTP協議12之快取代理

  我們仔細來看一下這張圖,在快取失效後的驗證節點,如果需要驗證的話,會額外的去檢視是否是代理快取,並決定後續是查詢代理還是查詢源伺服器。繼而判斷中間代理的快取邏輯,是private還是public。然後繼續判斷各自路徑的maxage。

  仔細看完這張圖後,我們發現,整個驗證的核心節點和關鍵步驟其實是沒有什麼變化的,只是在判斷的節點中額外的加入了是否需要代理的邏輯罷了。大家好好消化,仔細區分。

二、客戶端的快取控制。

  客戶端的快取控制相比於源伺服器的快取控制,在加入了代理的場景下要相對簡單一些。對於客戶端來說,代理伺服器就是伺服器,所以max-age、no-store、no-cache這三個屬性,跟面向源伺服器時是一樣的。

  但是關於快取的生存時間,在代理伺服器上的約束和條件則多了兩個新的屬性“max-stale”和“min-fresh”。

  “max-stale”的意思是如果代理上的快取過期了也可以接受,但不能過期太多,超過 x 秒也會不要。“min-fresh”的意思是快取必須有效,而且必須在 x 秒後依然有效。

  有的時候客戶端還會發出一個特別的“only-if-cached”屬性,表示只接受代理快取的資料,不接受源伺服器的響應。如果代理上沒有快取或者快取過期,就應該給客戶端返回一個 504(Gateway Timeout)。

  我們還是來看張圖鞏固下、串聯一下這些知識:

 真正“搞”懂HTTP協議12之快取代理

  這張圖就是完整的客戶端設定快取約束的判定流程,大家一定要對比著有代理和沒代理有啥區別來對照著學習。

三、小結

  代理伺服器可能會在響應報文中加入X-Cache、X-Hit等自定義的頭欄位,標識快取是否命中和命中率,方便觀察快取代理的工作情況。

  另外,大家還記得Vary這個頭欄位麼,我們在之前的章節中學到過,它是內容協商後的結果,相當於報文的一個版本標記,快取代理必須要儲存這些不同的版本,當再收到相同的請求時,代理就會讀取快取裡的Vary,對比請求頭裡的欄位判斷是否一致,是否可以返回快取的資料。

  還有一個“Purge”問題,也就是“快取清理”,他對於代理也是非常重要的功能,比如:過期的資料、版本老舊、快取危險資料等等。通常情況下,會使用一個自定義的PURGE方法,來刪除對應連線的快取資料。

  好啦~到這裡,我們學完了快取代理的相關頭欄位,其實並不怎麼複雜,只是在原有的快取的頭欄位的基礎上,加上了一些源伺服器和客戶端設定的頭欄位屬性,讓我們得控制快取的細粒度更精細一些。

  最後,我再次強調,大家要對比著和快取那一章節來看圖學習。

  有關於HTTP/1.1的內容基本上就告一段落了。下一篇我們一起去領略一下HTTP/2的風采。

相關文章