1、前言
咱們在平常的抓包過程當中常常能夠看到以Accept開頭的請求首部,好比:Accept-Language 有一個q值,確定有人好奇在HTTP規範中爲何要定義這個q值;還有在響應首部有一個名爲Vary的首部,這個首部又有什麼意義?如圖所示:
2、內容協商
要講清楚這兩個問題,咱們須要引入HTTP協議的內容協商概念:某一資源,服務器有多個版本,客戶端告知服務器本身的偏好,服務器根據偏好選擇合適的版本響應客戶端的請求。內容協商技術一般有三種實現方案:
(1)客戶端驅動
客戶端發起請求,服務器發送可選項列表,客戶端做出選擇後在發送第二次請求。
優勢:比較容易實現
缺點:增長了時延,至少要發送兩次請求,第一次請求獲取資源列表,第二次獲取選擇的副本。
(2)服務器驅動
服務器檢查客戶端的請求首部集並決定提供哪一個版本的頁面。
優勢:比客戶端驅動的協商要快。HTTP提供了q機制,容許服務器近似匹配,還提供了vary首部供服務器告知下游的設備(如代理服務器)如何對請求估值。
缺點:首部集不匹配,服務器要作猜想
(3)透明協商
某個中間設備(一般是緩存代理)表明客戶端進行協商
優勢:免除了web服務器的協商開銷,比客戶端驅動的協商要快。
缺點:HTTP並無提供相應的規範
其中,服務器驅動的解決方案應用的較爲普遍。
3、通用的內容協商首部
客戶端發送Accept首部集發送用戶的偏好信息,服務器發送實體首部集匹配客戶端的Accept首部集:
Accept Content-type
Accept-Language Content-Language
Accept-Encoding Content-Encoding
4、q質量值的應用場景
假設客戶端的Accept-Language指定的是西班牙語,可是服務端只有英語與法語版本,這個客戶端但願在沒有西班牙語的時候優先返回英語。這就意味着,咱們須要一種HTTP機制更詳細的描述偏好。這種機制就是質量值(q值)。示例以下:
Accept-Language: en;q=0.5, fr;q=0.0, nl;q=1.0, tr;q=0.0
這個首部表示:用戶最願意接受荷蘭語(nl),英文也行(en),就是不肯意接受法語(fr)或者土耳其語(tr)
q值的範圍從0.0~1.0(1.0優先級最高)
5、vary首部的應用場景
服務器的決策不是依據Accept首部集(常規的內容協商首部集),而是好比Accept-Encoding
假設整個請求過程是這樣的:客戶端 -> 代理服務器(具有緩存功能) ->web服務器。
第一個支持gzip壓縮的客戶端向中間代理服務器發送請求,代理服務器轉發該請求,向web服務器拉取內容,拿到內容後代理服務器緩存該內容(因爲請求首部有Accept-Encoding: gzip 因此內容會被壓縮)。
第二個不支持gzip壓縮的客戶端也向中間代理服務器發送同一個請求,代理服務器發現該請求已經被緩存了,因而就把壓縮後的內容響應給該客戶端。悲劇了,由於該客戶端根本不支持gzip壓縮,也就無法解壓。
6、Vary首部的工做原理
HTTP的Vary響應首部中列出了全部客戶端請求首部,緩存服務器能夠用這些首部來選擇文檔或者產生定製的內容。好比:若給客戶端的響應內容取決於Accept-Encoding,Vary首部就必須包含Accept-Encoding。
當新的請求到達時,緩存服務器會根據內容協商首部集來尋找最佳匹配。可是在把文檔提供給客戶端以前,它必須檢查web服務器有沒有在已緩存響應中發生Vary首部。若是有,那麼新請求中那些首部的值必須與舊的已緩存請求裏相應的首部相同。由於web服務器可能會根據客戶端請求的首部來改變響應,爲了實現透明協商,
緩存服務器必須爲每一個已緩存變體保存客戶端請求首部和相應的服務器響應首部。
簡單的講:
web服務器添加響應首部Vary: Accept-Encoding 告知代理服務器根據客戶端的請求首部Accept-Encoding緩存不一樣的版本,這樣下次客戶端請求同一資源時,根據Accept-Encoding選擇相應的緩存版本響應。
其實咱們還能夠禁用中間實體的緩存功能解決該問題:
web服務器設置響應首部: Cache-Control: private
一般添加Vary首部的解決方案比較通用,由於咱們仍是但願充分利用中間實體的緩存功能的。
7、參考資料
書籍:《HTTP權威指南》