HTTP 協議與 TCP/UDP 類似,需要在實際傳輸的數據前附加一些頭數據。不過與 TCP/UDP 不同的是,HTTP 協議是一個“純文本”協議,頭部數據都是 ASCII 碼的文本,可以直接閱讀。
報文結構
HTTP 協議的請求報文和響應報文基本相同,由三大部分組成:
- 起始行(start line):描述請求和響應的基本信息;
- 頭部字段集合(header):使用 key-value 形式更詳細的說明報文;
- 消息正文(entity):實際傳輸的數據,可以是文本、圖片、視頻等。
其中前兩部分起始行和頭部字段經常合稱為“請求頭”或“響應頭”,消息正文又稱為“body”。
HTTP 協議規定報文必須有 header,可以沒有 body,而且在 header 之后必須要有一個“空行(CRLF)”。

請求行
GET / HTTP/1.1
請求行由三部分構成:
- 請求方法:如 GET、POST,表示對資源的操作;
- 請求目標:通常是一個 URI,標記了請求方法要操作的資源;
- 版本號:表示報文使用的 HTTP 協議版本。
這三部分通常使用空格(space)來分隔,最后要用 CRLF 換行表示結束。

狀態行
HTTP/1.1 200 OK
響應報文中的起始行稱為“狀態行”,意思是服務器響應的狀態。
狀態行也是由三部分構成:
- 版本號:表示報文使用的 HTTP 協議版本;
- 狀態碼:一個三位數,表示處理的結果。如 200 是成功,500 是服務器錯誤。
- 原因:作為數字狀態碼補充,是更詳細的解釋。

頭部字段
請求行或狀態行再加上頭部字段集合就構成了 HTTP 報文里完整的請求頭或響應頭。
頭部字段是 key-value 的形式,key 和 value 之間用“:”分隔,最后用 CRLF 換行表示字段結束。
HTTP 頭字段非常靈活,不僅可以使用標准里的 Host、Connection 等已有頭,還可以任意添加自定義頭,這給 HTTP 協議帶來了無限拓展可能。
常用頭字段
基本可以分為四大類:
- 通用字段:在請求頭和響應頭里都可以出現;
- 請求字段:只能出現在請求頭里,進一步說明請求信息或額外的附加條件;
- 響應字段:只能出現在響應頭里,補充說明響應報文的信息;
- 實體字段:它實際上屬於通用字段,但專門描述 body 的額外信息。
Host
Host 屬於請求字段,只能出現在請求頭里,同時也是唯一一個 HTTP/1.1 規范里要求必須出現的字段。
Host 字段告訴服務器這個請求該由哪個主機來處理,當一台計算機上托管了多個虛擬主機的時候,服務器端就需要用 Host 字段來選擇,有點像一個簡單的“路由重定向”。
User-Agent
User-Agent 屬於請求字段,只出現在請求頭里。描述發起 HTTP 請求的客戶端,服務器可以依據它來返回最適合此瀏覽器顯示的頁面。
Date
Date 是一個通用字段,但通常出現在響應頭里,表示 HTTP 報文創建的時間,客戶端可以使用這個時間再搭配其他字段決定緩存策略。
Server
Server 是響應字段,只能出現在響應頭里。它告訴客戶端當前正在提供 Web 服務的軟件名稱和版本號。這個字段不是必須要出現的,因為這會把服務器的一部分信息暴露給外界。所以,有的網站響應頭里要么沒有這個字段,要么就給出一個完全無關的信息。
Content-length
Content-length 表示報文里 body 的長度,也就是請求頭或響應頭空行后面數據的長度。服務器看到這個字段,就知道了后續有多少數據,可以直接接收。如果沒有這個字段,那么 body 就是不定長的,需要使用 chunked 方式分段傳輸。
問題:
-
如果在拼 HTTP 報文的時候,在頭字段后多加了一個 CRLF,導致出現了一個空行,會發生什么?
答:在 header 下面第一個空行以后都會被當作 body 處理 -
頭字段“:”后面的空格可以有多個,那么為什么絕大多數情況下都只使用一個空格呢?
答:頭部多一個空格就會多一個傳輸的字節,去掉無用的信息,保證傳輸的頭部字節數盡量小。