鮮為人知的HTTP協議頭欄位詳解大全「原創」

老錢發表於2018-03-24

繼上篇講了HTTP協議的基礎之後,本篇重點介紹一下HTTP常用的Header。

HTTP Header非常之多,很少有人能完全分清這些Header到底是幹什麼的。鑑於RFC檔案規範艱深晦澀難懂,本文對協議規範中列出的HTTP Header進行了梳理,用通俗的語言進行表達,便於讀者吃透HTTP協議。

作者在閱讀RFC文件的時候發現了很多以前沒注意到的知識,估計做web開發的小夥伴們也大多忽視了這些知識,閱讀文字會給你們帶來很多意外的驚喜。

免責宣告:如果下面有那句話有不對的地方,還請噴少點口水。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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

鮮為人知的HTTP協議頭欄位詳解大全「原創」

Accept-Language

表示客戶端期望伺服器返回的內容的語言。很多大型網際網路公司是全球化的,它的技術文件一般有有多種語言,通過這個欄位可以實現文件的本地化,對國內使用者呈現簡體中文文件,對英語系使用者呈現英文文件。

Accept-Language:zh-CN,en-US;q=0.8,zh-TW;q=0.6
複製程式碼

表示大陸簡體中文優先,其次英語,再其次臺灣繁體中文

Content-Language

這個頭欄位內容是對Accept-Language的應答。伺服器通過此欄位告知客戶端返回的Body資訊的語言是什麼。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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頭資訊中作為資源的唯一標識來使用。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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,只是條件相反。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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服務節點,它常用於虛擬主機服務業務。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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和整個資源內容。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

Location

伺服器向客戶端傳送302跳轉的時候,總會攜帶Location頭資訊,它的值為目標URL。

HTTP/1.1 302 Temporary Redirect
Location: 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,可得出資源頁面之間複雜的跳轉鏈,它非常適合用於網頁的資料分析和路徑優化。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

Retry-After

伺服器升級時,來自客戶端的請求會直接給予503(Service Unavailable)錯誤,通過在返回頭裡面加入Retry-After欄位告知客戶端何時服務可以恢復正常訪問。Retry-After的頭可以是HTTP-Date,也可以是整數,表示多少秒後服務可以恢復正常訪問。瀏覽器在拿到這個值之後可以考慮增加一個定時器在未來的某個時間進行重試。

Server

用於返回伺服器相關的軟體資訊,來告知客戶端當前的HTTP服務是由某某軟體提供的,可以看成是一種軟體廣告。 RFC協議裡對這個頭資訊做了警告:暴露出伺服器資訊可能會導致黑客更易於攻擊你的服務,建議謹慎使用。

User-Agent

攜帶當前的使用者代理資訊,一般包含瀏覽器、瀏覽器核心和作業系統的版本型號資訊。它和Server頭是對應的,一個是表達伺服器資訊,一個是表達客戶端資訊。伺服器可以根據使用者代理資訊統計出網頁服務的瀏覽器、作業系統的使用佔比情況,伺服器也可以根據UA的資訊來定製不一樣的內容。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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=
複製程式碼

鮮為人知的HTTP協議頭欄位詳解大全「原創」

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頭裡面最複雜的一個頭了。這個頭既可以用於請求,也可以用於響應。在請求和響應的取值不一樣,分別代表了不同的意思。

  1. no-cache 如果no-cache沒有指定值,那就表示不允許快取。對於請求來說,伺服器不得使用快取內容直接返回。對於響應來說,客戶端不得快取響應的資源內容。如果no-cache指定了值,那就表示值對應的頭資訊不得使用快取,其它的資訊還是可以快取的。告知對方我只要新鮮剛出浴的資料。
  2. no-store 告知對方不要持久化請求/響應資料到其它地方,這種資訊是敏感的,要保持它的易失性。告知對方記在心裡(memory)就行,別寫在紙上(disk)。
  3. no-transform 告知對方不要轉換資料。比如客戶端上傳了raw影象資料,伺服器一般都會選擇性壓縮影象資料進行儲存。no-transform告知對方保留原始資料資訊,不要進行任何轉換。告知對方不要亂動我發過來的東西。
  4. only-if-cached 用於請求頭,告知伺服器只要那些已經快取的內容,不要去reload。如果沒有快取內容就返回504 Gateway Timeout錯誤。表示客戶端不想太麻煩伺服器,有就給,沒就算了。
  5. max-age 用於請求頭。限制快取內容的年齡,如果超過max-age年齡的,需要伺服器去reload內容資源。這叫客戶端的年齡歧視。
  6. max-stale 用於請求頭。客戶端允許伺服器返回快取已過期的資源內容,但是限定了最大過期時間。表示客戶端雖然很寬容,那是也是有限度的。
  7. min-fresh 用於請求頭。客戶端限制伺服器不要那些即將過期的資源內容。就好比我們去超市買牛奶,如果牛奶快過期了雖然還在保質期內我們們也就不會考慮。
  8. public 用於響應頭。表示允許客戶端快取響應資訊,並可以給別人使用。比如代理伺服器快取靜態資源供所有代理使用者使用。
  9. private 用於響應頭。表示僅允許客戶端快取響應資訊給自己使用,不得分享給別人。這樣是為了禁止代理伺服器進行快取,而允許客戶端自己快取資源內容。意思是你個人留著用就行,別借給別人用。

鮮為人知的HTTP協議頭欄位詳解大全「原創」

因為HTTP協議細節非常繁多,以上文字並不能完全將HTTP的所有的頭部細節都講清楚。後續【碼洞】會繼續更新更加精細的文章,建議讀者關注公眾號【碼洞】第一時間看到相關文章。

相關文章