HTTP 協議完全解析

王菜花發表於2019-02-12

HTTP 的全稱是 HyperText Transfer Protocol (超文字傳輸協議)的縮寫,是一種建立在 TCP 上的無狀態連線。HTTP 是網際網路的基礎協議,用於客戶端與伺服器之間的通訊,它規定了客戶端和伺服器之間的通訊格式,包括請求與響應的格式。

基本的工作流程是客戶端傳送一個 HTTP 請求,服務端收到請求開始處理,處理結束返回給客戶端結果,客戶端對結果進行處理並展示。

現在最流行的 HTTP 版本還是 1997 年釋出的 HTTP/1.1。

HTTP 協議完全解析

目錄

  • HTTP 的工作方式
  • HTTP 的報文格式
  • HTTP 起始行
  • HTTP 請求方法
  • HTTP 響應碼
  • HTTP Headers

一、 HTTP 的工作方式

1.1 請求過程

客戶端向服務端傳送一段請求報文,服務端收到後,返回響應報文,客戶端對響應內容進行展示。

HTTP 協議完全解析

一個 HTTP 的請求必定是由客戶端發起,伺服器端回覆響應。伺服器在沒有接收到請求之前不會傳送響應。

名詞解釋

客戶端:請求訪問文字或影象等資源的一端。

服務端:提供資源響應的一端。

資源:網路上的一切內容都是資源,無論是圖片文字還是動態程式碼。

1.2 請求方式

web 瀏覽器請求:

HTTP 協議完全解析

請求過程如下 ⬇️

  1. 使用者輸入地址後回車或點選連結
  2. 瀏覽器拼裝 HTTP 報文併傳送請求給服務器
  3. 服務器處理請求後,傳送響應報文給瀏覽器
  4. 瀏覽器解析響應報文並使用渲染引擎顯示到介面

APP 客戶端請求:

HTTP 協議完全解析

請求過程如下 ⬇️

  1. 使用者點選或介面自動觸發聯網需求
  2. Android 程式碼呼叫拼裝 HTTP 報文併傳送請求到服務器
  3. 服務器處理請求後傳送響應報文給手機
  4. Android 程式碼處理響應報文並作出相應處理(如儲存資料、加工資料、顯示資料到介面)

1.3 報文是什麼

報文是在 HTTP 應用程式之間傳送的資料塊。這些資料塊以一些文字的元資訊 (meta 標籤中的資訊) 開頭,描述了報文的內容及含義。

每條報文都包含一條來自於客戶端的請求,或者一條來自於服務端的響應

它由 3 部分組成:對報文進行描述的「起始行」、包含屬性的「首部(Header)」以及可選的、包含資料的「主體(body)

HTTP 協議完全解析

二、HTTP 的報文格式

2.1 請求報文的格式

<method> <path> <HTTP version>
<headers>

<entity-body>
複製程式碼

2.2 響應報文的格式

(注意,只有起始行的語法與請求報文有所不同)

<HTTP version> <status code> <reason-phrase>
<headers>

<entity-body>
複製程式碼

下面是對各部分的簡要描述,後面會詳細介紹。

  • 方法 (method) 客戶端希望伺服器對資源執行的動作,常見的方法有 Get、Post、HEAD 等。
  • 請求路徑 (path) 請求的 URL 描述了要對哪個資源執行這個方法,是給伺服器看的。
  • HTTP 版本(HTTP version)
  • 狀態碼(status code) 不同狀態碼對應不同的響應狀態
  • 原因短句(reason-phrase) 對狀態碼進行簡單的描述。
  • 首部(headers) 包含許多鍵值對,是對響應資料的一些格式資訊。

三、 Method(請求方法)

最常見的請求方法就是 GETPOST了。除此之外還有 PUTDELETEHEAD 等。

GET

  • 最常見的請求方式
  • 指定請求路徑,向伺服器請求資源
  • 只獲取資源,不對伺服器資料進行修改
  • 不傳送 body
GET  /users/1  HTTP/1.1
Host: api.github.com
複製程式碼

對應的 Retrofit 的程式碼:

@GET("/users/{id}")
Call<User> getUser(@Path("id") String id, @Query("gender") String gender);
複製程式碼

Post

  • 使用者增加或者修改資源
  • 包含 body,傳送給伺服器的內容寫在 body 裡面
POST  /users  HTTP/1.1
Host: api.github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
複製程式碼

對應的 Retrofit 的程式碼:

@FormUrlEncoded
@POST("/users")
Call<User> addUser(@Field("name") String name, @Field("gender") String
gender);
複製程式碼

PUT

  • 用於修改資源
  • 包含 body,傳送給伺服器的內容寫在 body 裡面
PUT  /users/1  HTTP/1.1
Host: api.github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
複製程式碼

對應的 Retrofit 的程式碼:

@FormUrlEncoded
@PUT("/users/{id}")
Call<User> updateGender(@Path("id") String id, @Field("gender") String
gender);
複製程式碼

DELETE

  • 用於刪除資源
  • 不傳送 body
DELETE  /users/1  HTTP/1.1
Host: api.github.com
複製程式碼

對應的 Retrofit 的程式碼:

@DELETE("/users/{id}")
Call<User> getUser(@Path("id") String id, @Query("gender") String gender);
複製程式碼

HEAD

  • HEADGET 的使用方式完全相同。
  • 區別在於,HEAD 請求的返回響應中沒有 Body
  • 用途:比如下載需求,返回的 Headers 中有下載內容的大小,可以用於顯示進度。

小知識點

GETPUTDELETE 都是冪等操作,就是說,請求一次和請求多次的結果是一樣的。 比如,GET 請求一個資料,請求一次和請求十次返回的結果是一樣的,PUT 同樣修改一個資料,修改一次和修改十次,結果也都是一樣的。

四、狀態碼(status code)

狀態碼是對結果進行型別化的描述的,比如「請求成功」、「內容未找到」等 主要分為 5 類。

1xx:臨時性訊息。

100:繼續傳送
101:正在切換協議
複製程式碼

2xx:成功。

200:OK (最常見) 
201:建立成功
複製程式碼

3xx:重定向。

301:域名永久移動
302:暫時移動
304:內容未改變,請求被重定向到客戶端本地快取
複製程式碼

4xx:客戶端錯誤

400:客戶端請求錯誤,伺服器不理解請求的語法。
401:未授權,要求進行身份驗證。
403:被禁止,伺服器拒絕請求。
404:找不到內容,伺服器找不到請求的網頁。(最常見)
複製程式碼

5xx:伺服器錯誤

500:伺服器內部錯誤 (最常見)
503:服務不可用
複製程式碼

五、首部(Headers)

首部包含多個請求頭,是用來描述訊息的後設資料(meta data)。

首部欄位有很多,主要分為以下幾類:

  • 通用首部 => 提供了與報文相關的最基本的資訊
  • 請求首部 => 只在請求報文中有意義的首部
  • 響應首部 => 只在響應報文中有意義的首部
  • body 首部 => 描述 body 的首部

下面我們就說一些比較常用的。

5.1 通用首部

Date

提供日期和時間標誌,說明報文是在什麼時間建立的。

Date: Tue, 12 Feb 2019 07:32:07 GMT
複製程式碼

Connection

允許客戶端和伺服器指定與請求/響應連線有關的選項。

Connection: keep-alive
複製程式碼

其他通用首部

Via : 顯示報文經過的中間節點(代理、閘道器)。

via: cache25.l2ot7-1[0,304-0,H], cache25.l2ot7-1[1,0], cache5.us14[342,200-0,H]
複製程式碼

Transfer-Encoding : 告知接收端為了保證報文的可靠傳輸,對報文采用了什麼編碼方式。

Transfer-Encoding: chunked
複製程式碼

Cache-Control : 指定快取的控制方式。

cache-control: no-store, no-cache, must-revalidate, proxy-revalidate
複製程式碼

5.2 請求首部

Host

給出了接收請求的伺服器的主機名和埠。(注意:不是在網路上用於定址的,⽽是在目標服務器上定位子服務器。)

Host: api.github.com
複製程式碼

Accept

用來告訴服務端客戶端會接受的媒體型別,包括客戶端需要什麼,可以使用什麼,以及不想要什麼。

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

'*' 用來表示萬用字元。
;q= (q-factor weighting)
值代表優先順序,用相對質量價值表示,又稱為權重。
複製程式碼

Accept-Charset

用來告知伺服器,客戶端可以處理的字符集型別。

Accept-Charset: utf-8, iso-8859-1;q=0.5
複製程式碼

Accept-Encoding

用來將客戶端能夠理解的內容編碼方式告知伺服器,服務端會選擇一個客戶端提議的方式。

Accept-Encoding: gzip, deflate, br

gzip:表示採用 Lempel-Ziv coding (LZ77) 壓縮演算法,以及32位CRC校驗的編碼方式。
compress:採用 Lempel-Ziv-Welch (LZW) 壓縮演算法。
deflate:採用 zlib 結構和 deflate 壓縮演算法。
br:表示採用 Brotli 演算法的編碼方式。
identity:用於指代自身(例如:未經過壓縮和修改)。除非特別指明,這個標記始終可以被接受。
複製程式碼

Accept-Language

用來告訴伺服器,客戶端能夠理解哪些語言

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

Range

告訴伺服器,客戶端要獲取哪段資料。 主要用於:斷點續傳多執行緒下載

語法:
Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>
<unit>:範圍所採用的單位,通常是位元組(bytes)。
<range-start>:一個整數,表示在特定單位下,範圍的起始值。
<range-end>:一個整數,表示在特定單位下,範圍的結束值。這個值是可選的,如果不存在,表示此範圍一直延伸到文件結束。

Range: bytes=200-1000, 2000-6576, 19000-
複製程式碼

From

提供了客戶端使用者的 E-mail 地址, 用處:比如你有一個爬蟲程式,那麼 Form 首部應該隨請求一起傳送,這樣的話,在伺服器遇到問題的時候,例如爬蟲傳送了過量的、不希望收到的或者不合法的請求時,站點管理員可以聯絡到你。

5.3 響應首部

Server

包含了處理請求的源頭伺服器所用到的軟體相關資訊

Server: Apache-Coyote/1.1
複製程式碼

Set-Cookie

用來由伺服器端向客戶端傳送 cookie。

會話期 cookies 將會在客戶端關閉時被移除。 
會話期 cookie 不設定 Expires 或 Max-Age 指令
Set-Cookie: sessionid=38afes7a8; HttpOnly; Path=/

持久化 Cookie 不會在客戶端關閉時失效,而是在特定的日期(Expires)或者經過一段特定的時間之後(Max-Age)才會失效。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
複製程式碼

Accept-Ranges

響應中出現,表示服務器支援按位元組來取範圍資料

語法:
Accept-Ranges: bytes
Accept-Ranges: none
none:不支援任何範圍請求單位,由於其等同於沒有返回此頭部,因此很少使用。
bytes:範圍請求的單位是 bytes (位元組)。

Accept-Ranges: bytes
複製程式碼

5.4 Body 首部

由於請求與響應中都可以包含 body部分,所以在請求報文與響應報文中都可以出現這部分欄位。

Location

指定的是需要將頁面重新定向至的地址。一般在響應碼為 3xx 的響應中才會有意義。

Location: /index.html
複製程式碼

Content-Type

告訴客戶端實際返回的內容的內容型別。 主要分為 4 類。

  • text/html

請求 Web ⻚面時返回響應的型別,Body 中返回 html 文字。

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 853
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
複製程式碼
  • x-www-form-urlencoded

Web ⻚面純⽂本表單的提交方式

POST  /users  HTTP/1.1
Host: api.github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
name=xxtlant&gender=male
複製程式碼
  • multitype/form-data

Web ⻚面含有⼆制⽂件時的提交方式。

POST  /users  HTTP/1.1
Host: hencoder.com
Content-Type: multipart/form-data; boundary=----
WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 2382
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="name"
rengwuxian
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="avatar"; filename="avatar.jpg"
Content-Type: image/jpeg
JFIFHHvOwX9jximQrWa......
------WebKitFormBoundary7MA4YWxkTrZu0gW--
複製程式碼
  • application/json , image/jpeg , application/zip ...

單項內容(⽂本或非⽂本都可以),用於 Web Api 的響應或者 POST / PUT 的請求。

請求中提交 JSON

POST /users HTTP/1.1
Host: api.github.com
Content-Type: application/json; charset=utf-8
Content-Length: 38
{"name":"xxtlant","gender":"male"}
複製程式碼

響應中返回 JSON

Date: Tue, 12 Feb 2019 08:04:14 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Server: GitHub.com
Status: 200 OK

{"login": "xxtlant",
"id": 18342980,
"node_id": "MDQ6VXNlcjE4MzQyOTgw",
"avatar_url": "https://avatars2.githubusercontent.com/u/18342980?v=4",
"gravatar_id": "",
....
複製程式碼

請求中提交⼆進位制內容

POST /user/1/avatar HTTP/1.1
Host: hencoder.com
Content-Type: image/jpeg
Content-Length: 1575
JFIFHH9......
複製程式碼

相應中返回⼆進位制內容

HTTP/1.1 200 OK
content-type: image/jpeg
content-length: 1575
JFIFHH9......
複製程式碼

Content-length

用來指明傳送給接收方的訊息主體的大小。

Content-Length: <length>
複製程式碼

Content-Encoding

用於對特定媒體型別的資料進行壓縮。 這個訊息用來告知客戶端應該怎樣解碼才能獲取在 Content-Type 中的媒體型別內容。

Content-Encoding: gzip

其值受 Accept-Encoding 影響
複製程式碼

與此對應,Content-Language 也與 Accept-Language 對應。

六、參考連結

相關文章