鮮為人知的HTTP協議頭欄位詳解大全
繼上篇講了HTTP協議的基礎之後,本篇重點介紹一下HTTP常用的Header。
HTTP Header非常之多,很少有人能完全分清這些Header到底是幹什麼的。鑒於RFC文件規範艱深晦澀難懂,本文對協議規範中列出的HTTP Header進行了梳理,用通俗的語言進行表達,便於讀者吃透HTTP協議。
作者在閱讀RFC文檔的時候發現了很多以前沒注意到的知識,估計做web開發的小夥伴們也大多忽視了這些知識,閱讀文本會給你們帶來很多意外的驚喜。
免責聲明:如果下面有那句話有不對的地方,還請噴少點口水。
Accept
表示客戶端期望伺服器返回的媒體格式。客戶端期望的資源類型伺服器可能沒有,所以客戶端會期望多種類型,並且設置優先順序,伺服器根據優先順序尋找相應的資源返回給客戶端。
# 注意:先逗號分割類型,再分號分割屬性Accept: audio/*; q=0.2, audio/basic
表示audio/basic類型的資源優先,如果沒有,就隨便其它什麼格式的audio資源都可以。q的取值範圍是(0-1],其具體值並沒有意義,它僅用來排序優先順序,如果沒有q,默認q=1,也就是最高優先順序。
Accept-Charset
表示客戶端期望伺服器返回的內容的編碼格式。它同Accept頭一樣,也可以指定多個編碼,以q值代表優先順序。
# 注意:先逗號分割類型,再分號分割屬性Accept-Charset: utf8, gbk; q=0.6
表示utf8編碼優先,如果不行,就拿gbk編碼返回.
Content-Type
Content-Type是伺服器向客戶端發送的頭,代表內容的媒體類型和編碼格式,是對Accept頭和Accept-Charset頭的統一應答。
Content-Type: text/html; charset=utf8
表示返回的Body是個html文本,編碼為utf8
Accept-Language
表示客戶端期望伺服器返回的內容的語言。很多大型互聯網公司是全球化的,它的技術文檔一般有有多種語言,通過這個欄位可以實現文檔的本地化,對國內用戶呈現簡體中文文檔,對英語系用戶呈現英文文檔。
Accept-Language:zh-CN,en-US;q=0.8,zh-TW;q=0.6
表示大陸簡體中文優先,其次英語,再其次台灣繁體中文
Content-Language
這個頭欄位內容是對Accept-Language的應答。伺服器通過此欄位告知客戶端返回的Body信息的語言是什麼。
Content-Length
表示傳輸的請求/響應的Body的長度。GET請求因為沒有Body,所以不需要這個頭。攜帶Body的並且可以提前知道Body長度的請求/響應必須帶上這個欄位,以便對方可以方便的分辨出報文的邊界,也就是Body數據何時結束。如果Body太大,需要邊計算邊傳輸,不到最後計算結束是無法知道整個Body大小的,這個時候可以使用http分塊傳輸,這個時候也是不需要Content-Length欄位的。
Content-Location
當客戶端請求的資源在伺服器有多個地址時,伺服器可以通過Content-Location欄位告知客戶端其它的可選地址。這個欄位比較少見。
Content-MD5
在Header中提供這個信息是用來做Body內容校驗。它表示Body信息被md5演算法處理後的base64字元串。這個欄位也比較少見。因為校驗機制在TCP層已經有實現了,再來一層校驗並沒有多大意義。另外資源的md5值往往用來放在後面的ETag頭信息中作為資源的唯一標識來使用。
Date
如果伺服器沒有緩存,那麼Date就是響應的即時生成時間。如果伺服器設有緩存,那麼Date就是響應內容被緩存的時間。它必須符合規範里定義的特定格式,這種格式叫著HTTP-Date,不支持隨意定義自己的時間格式。
Date: Tue, 15 Nov 1994 08:12:31 GMT
Age
表示資源緩存的年齡,也就是資源自緩存以來到現在已經過去了多少時間,單位是秒。
Age: 86400
Expires
伺服器使用Expect頭來告知對方資源何時失效。如果它的值等於Date頭的值,就表示資源已經實效。
Expires: Thu, 01 Dec 1994 16:00:00 GMT
ETag
資源標籤,每個資源可以提供多個標籤信息。它一般用來和下面的If-Match和If-None-Match配合使用,用來判斷緩存資源的有效性。比較常見的標籤是資源的版本號,比如可以拿資源數據的md5校驗碼作為版本號。
If-Match
If-Match的值一般是上面提到的ETag的值,它常用於HTTP的樂觀鎖。所謂HTTP樂觀鎖,是指客戶端先GET這個資源得到ETag中的版本號,然後發起一個資源修改請求PUT|PATCH時通過If-Match頭來指定資源的版本號,如果伺服器資源滿足If-Match中指定的版本號,請求就會被執行。如果不滿足,說明資源被並發修改了,就需要返回狀態碼為412 Precondition failed 的錯誤。客戶端可以選擇放棄或者重試整個過程。
If-None-Match
類似於If-Match,只是條件相反。
Allow
表示資源支持訪問的HTTP Method類型。它是伺服器對客戶端的建議,告知對方請使用Allow中提到的Method來訪問資源。
Allow: GET, HEAD, PUT
Connection
當客戶端和伺服器需要協商連接的屬性時,可以使用Connection頭部。比較常用的一個值是close,用來通知對方在當前請求結束後關閉連接。
Connection: close
Expect
用於請求發送之前向伺服器詢問許可。譬如要向伺服器發送一個很大的文件而不確定是否超出限制,就可以在請求頭裡攜帶一個Expect頭部
Expect: 100-continue
如果伺服器說不行,就會返回417 Expectation Failed錯誤告知客戶端放棄。如果可以那就返回100 continue狀態碼告知客戶端放馬過來吧,於是客戶端就會繼續上傳Body內容。如果伺服器提前收到Body內容就會放棄返回100 continue響應。
From
該欄位一般用來標記請求發起者的郵件地址,相當於給請求賦予一個責任人。如果伺服器發現請求存在問題,就會通過此欄位聯繫到發起人進行處理。因為郵件地址涉及到隱私信息,所以請求攜帶From頭需要徵得用戶的同意。RFC協議建議所有的機器人代理髮起的請求應該攜帶此頭部,以免遇到問題時可以找到責任人。不過如果是惡意的機器人,估計這樣的建議也只是耳邊風而已。
Host
RFC協議規定所有的HTTP請求必須攜帶Host頭,即使Host沒有值,也必須帶上這個Host頭附加一個空串,如果不滿足,應用伺服器應該拋出400 Bad Request。協議雖然這樣規定,不過大部分網關或者伺服器都比較仁慈,既然沒有指定Host欄位,那就給你默認加上一個。
網關代理可以根據不同的Host值轉發到不同的upstream服務節點,它常用於虛擬主機服務業務。Last-Modified
標記資源的最近修改時間,它和Date比較類似,區別是Last-Modified代表修改時間,而Date是創建時間。
If-Modified-Since
瀏覽器向伺服器請求靜態資源時,如果瀏覽器本地已經有了緩存,就會攜帶If-Modified-Since頭,值為資源的Last-Modified時間,詢問伺服器該資源自從這個Last-Modified時間之後有沒有被修改。如果沒有修改過,就會向瀏覽器返回304 Not Modified通知瀏覽器可以放心使用緩存內的資源。如果資源修改過,那就像正常的GET請求一樣,攜帶資源的內容返回200 OK。
If-Unmodified-Since
類似於If-Modified-Since,意義相反。區別是當伺服器資源條件不滿足時,不是返回304 Not Modified,而是返回412 Precondition Failed。
Range
支持斷點續傳的伺服器必須處理Range頭,它表示客戶端請求資源的一部分時指定的請求位元組範圍。它是客戶端向伺服器發送的請求頭。
Range: bytes=500-999
Content-Range
針對上面的Range頭,伺服器響應客戶端時也需提供相應的Content-Range頭,表示傳輸的Body數據在整體資源塊中的位元組範圍。比如下面的例子表示該資源總共有47022位元組,當前響應的內容是21010-47021位元組之間的內容。
Content-Range: bytes 21010-47021/47022
之所以是47021而不是47022是因為offset是以0開始的,47021就是最後一個位元組。
If-Range
在斷點續傳時,為確保連續2個請求之間伺服器資源本身沒有發生變化,需要If-Range頭帶上ETag的資源版本號。伺服器資源根據這個版本號來判定資源是否改變了。如果沒變,就返回206 Partial Content將部分資源返回。如果資源變了,那就相當於一個普通的GET請求,返回200 OK和整個資源內容。
Location
伺服器向客戶端發送302跳轉的時候,總會攜帶Location頭信息,它的值為目標URL。
HTTP/1.1 302 Temporary RedirectLocation: https://www-temp.example.org/
Max-Forwards
用來限定網關或者代理的層數,也就是最大轉發次數。HTTP每經過一個網關或者代理層,Max-Forwards值就要減1。如果nginx接收到前端請求的時候Max-Forwards已經等於0,那麼它就不應該再將請求轉發到upstream指定的服務節點上。
Pragma
這個頭是比較常見的,在前端開發模式下經常會加上這個頭部。
Pragma: no-cache
當網關收到一個帶有這樣請求的頭部時,即使內部存在該請求資源的緩存並且有效也不可以直接發送給客戶端,而必須轉發給後面的upstream進行處理。
不過如果真的所有的網關都遵循這個協議的話,攻擊是很容易構造的,所以它一般僅用於開發模式,防止靜態資源修改後前端得不到即時更新。其它值的pragma值沒有遇到過。Referer
Referer是非常常用的頭,它表示請求的發起來源URI,也就是當前頁面資源的父頁面。如果你從A頁面跳轉到B頁面,那麼請求B頁面的請求頭裡面就會有Referer信息,它的值就是A頁面的訪問地址。通過追蹤Referer,可得出資源頁面之間複雜的跳轉鏈,它非常適合用於網頁的數據分析和路徑優化。
Retry-After
伺服器升級時,來自客戶端的請求會直接給予503(Service Unavailable)錯誤,通過在返回頭裡面加入Retry-After欄位告知客戶端何時服務可以恢復正常訪問。Retry-After的頭可以是HTTP-Date,也可以是整數,表示多少秒後服務可以恢復正常訪問。瀏覽器在拿到這個值之後可以考慮增加一個定時器在未來的某個時間進行重試。
Server
用於返回伺服器相關的軟體信息,來告知客戶端當前的HTTP服務是由某某軟體提供的,可以看成是一種軟體廣告。
RFC協議里對這個頭信息做了警告:暴露出伺服器信息可能會導致黑客更易於攻擊你的服務,建議謹慎使用。User-Agent
攜帶當前的用戶代理信息,一般包含瀏覽器、瀏覽器內核和操作系統的版本型號信息。它和Server頭是對應的,一個是表達伺服器信息,一個是表達客戶端信息。伺服器可以根據用戶代理信息統計出網頁服務的瀏覽器、操作系統的使用佔比情況,伺服器也可以根據UA的信息來定製不一樣的內容。
Transfer-Encoding
傳送Body信息時需要對Body數據採取何種變換。當HTTP對Body進行分塊傳送時,需要增加下面的頭部信息才可以進行分塊傳送。其它類型目前沒有遇到過。
Transfer-Encoding: chunked
Upgrade
伺服器建議客戶端升級傳輸協議。比如當客戶端使用HTTP/1.0發送請求時,伺服器就可以建議客戶端升級到HTTP/1.1。
這個時候就可以使用Upgrade頭。客戶端收到這個Upgrade後就會將後續請求轉成HTTP/1.1格式繼續進行交流。可以支持多個參數,使用逗號分割即可。Upgrade: HTTP/1.1
當客戶端要和伺服器進行Websocket進行通訊時,在握手階段伺服器也會向客戶端發送Upgrade頭部信息,提示客戶端將協議切換到Websocket。
Upgrade: WebSocket
Vary
該頭部用於緩存控制。對於一些緩存伺服器,我們在請求里加入Vary參數可以告知緩存伺服器對不同的Vary參數的響應使用不同的緩存單元。比如Vary參數里放入編碼參數,那麼不同編碼的網頁就會有不同的緩存。Vary的值可以有多個,只要任意一個值不一樣就會有不同的緩存。
比如下面的這個例子告知緩存伺服器對不同語言和不同編碼的網頁響應使用不同的緩存單元。Vary: Accept-Encoding,Accept-Language
Via
該欄位用來標識一個請求經過的網關路由節點。如果這個請求經過了多個代理層,Via頭部就會有多個網關信息。
Warning
用於在響應中添加一些附加的警告信息,警告信息包含一個錯誤碼和錯誤說明。通用的一些錯誤碼在RFC協議中有具體規定。比如111號錯誤碼錶示緩存伺服器的緩存項目已經過期,並且嘗試reload資源,但是reload失敗了,所以只好返回了舊的已經過期的內容,這個時候就需要通過warning頭反饋客戶端。
Warning: 111 Revalidation failed
WWW-Authenticate
WWW-Authenticate是401 Unauthorized錯誤碼返回時必須攜帶的頭,該頭會攜帶一個問題Challenge給客戶端,告知客戶端需要攜帶這個問題的答案來請求伺服器才可以繼續訪問目標資源。這種問題Challenge可以自定義,比較常見的是Basic認證。
WWW-Authenticate: Basic realm=xxx
Basic指代base64加密演算法(不安全),realm指代認證範圍/場合/情景名稱。
Authorization
對於某些需要特殊許可權才能訪問的資源需要客戶端在請求里提供用戶名密碼的認證信息。它是對WWW-Authenticate的應答。
# value = base64(user_name:password)Authorization: Basic YWRtaW46YWRtaW4xMjM=
Proxy-Authenticate
同WWW-Authorization頭部,用於代理伺服器認證。
Proxy-Authorization
同Authorization頭部,用於代理伺服器認證。
ETag vs Last-Modified vs Expires
ETag一般攜帶的是資源的版本號,協議沒有具體規定版本號是什麼。它可以是資源的md5校驗碼,也可以是uuid,甚至可以是自增的數字,也可以是資源的修改時間。它的匹配方式是相等/不相等。因為伺服器需要維護版本號,取決的版本號是什麼,這可能是一個存儲和計算的負擔。
Last-Modified攜帶的資源的修改時間。它的匹配方式是大於/小於。如果是靜態資源文件,一般就是操作系統記錄的文件修改時間。
Expires是伺服器告知客戶端資源的過期時間。客戶端緩存的資源在這個時間之後自動過期,而不需要非得向伺服器確認一下是不是304 Not Modified才認為沒過期。
Cache-Control
這可能是HTTP頭裡面最複雜的一個頭了。這個頭既可以用於請求,也可以用於響應。在請求和響應的取值不一樣,分別代表了不同的意思。
- no-cache 如果no-cache沒有指定值,那就表示不允許緩存。對於請求來說,伺服器不得使用緩存內容直接返回。對於響應來說,客戶端不得緩存響應的資源內容。如果no-cache指定了值,那就表示值對應的頭信息不得使用緩存,其它的信息還是可以緩存的。告知對方我只要新鮮剛出浴的數據。
- no-store 告知對方不要持久化請求/響應數據到其它地方,這種信息是敏感的,要保持它的易失性。告知對方記在心裡(memory)就行,別寫在紙上(disk)。
- no-transform 告知對方不要轉換數據。比如客戶端上傳了raw圖像數據,伺服器一般都會選擇性壓縮圖像數據進行存儲。no-transform告知對方保留原始數據信息,不要進行任何轉換。告知對方不要亂動我發過來的東西。
- only-if-cached 用於請求頭,告知伺服器只要那些已經緩存的內容,不要去reload。如果沒有緩存內容就返回504 Gateway Timeout錯誤。表示客戶端不想太麻煩伺服器,有就給,沒就算了。
- max-age 用於請求頭。限制緩存內容的年齡,如果超過max-age年齡的,需要伺服器去reload內容資源。這叫客戶端的年齡歧視。
- max-stale 用於請求頭。客戶端允許伺服器返回緩存已過期的資源內容,但是限定了最大過期時間。表示客戶端雖然很寬容,那是也是有限度的。
- min-fresh 用於請求頭。客戶端限制伺服器不要那些即將過期的資源內容。就好比我們去超市買牛奶,如果牛奶快過期了雖然還在保質期內咱們也就不會考慮。
- public 用於響應頭。表示允許客戶端緩存響應信息,並可以給別人使用。比如代理伺服器緩存靜態資源供所有代理用戶使用。
- private 用於響應頭。表示僅允許客戶端緩存響應信息給自己使用,不得分享給別人。這樣是為了禁止代理伺服器進行緩存,而允許客戶端自己緩存資源內容。意思是你個人留著用就行,別借給別人用。
因為HTTP協議細節非常繁多,以上文字並不能完全將HTTP的所有的頭部細節都講清楚。後續【碼洞】會繼續更新更加精細的文章,建議讀者關注公眾號【碼洞】第一時間看到相關文章。
推薦閱讀: