真正“搞”懂HTTP協議12之緩存代理

  我們在前兩篇的內容中分別學習了緩存和代理,大致瞭解了緩存有哪些頭字段,代理是如何服務於服務器和客戶端的,那麼把兩者結合起來,代理緩存,也就是說代理服務器也可以緩存,當客戶端請求數據的時候,未必一定要追溯到源服務器上,代理服務器就可以直接把緩存的數據返回給客戶端。並且,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”屬性,否則客戶端和代理後面就無法使用條件請求來驗證緩存是否有效。

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

  我們仔細來看一下這張圖,在緩存失效後的驗證節點,如果需要驗證的話,會額外的去查看是否是代理緩存,並決定後續是查詢代理還是查詢源服務器。繼而判斷中間代理的緩存邏輯,是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)。

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

 

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

三、小結

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

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

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

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

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章