HTTP 的全稱是 HyperText Transfer Protocol (超文字傳輸協議)的縮寫,是一種建立在 TCP 上的無狀態連線。HTTP 是網際網路的基礎協議,用於客戶端與伺服器之間的通訊,它規定了客戶端和伺服器之間的通訊格式,包括請求與響應的格式。
基本的工作流程是客戶端傳送一個 HTTP 請求,服務端收到請求開始處理,處理結束返回給客戶端結果,客戶端對結果進行處理並展示。
現在最流行的 HTTP 版本還是 1997 年釋出的 HTTP/1.1。
目錄
- HTTP 的工作方式
- HTTP 的報文格式
- HTTP 起始行
- HTTP 請求方法
- HTTP 響應碼
- HTTP Headers
一、 HTTP 的工作方式
1.1 請求過程
客戶端向服務端傳送一段請求報文,服務端收到後,返回響應報文,客戶端對響應內容進行展示。
一個 HTTP 的請求必定是由客戶端發起,伺服器端回覆響應。伺服器在沒有接收到請求之前不會傳送響應。
名詞解釋
客戶端:請求訪問文字或影像等資源的一端。
服務端:提供資源響應的一端。
資源:網路上的一切內容都是資源,無論是圖片文字還是動態程式碼。
1.2 請求方式
web 瀏覽器請求:
請求過程如下 ⬇️
- 使用者輸入地址後回車或點選連結
- 瀏覽器拼裝 HTTP 報文併傳送請求給服務器
- 服務器處理請求後,傳送響應報文給瀏覽器
- 瀏覽器解析響應報文並使用渲染引擎顯示到介面
APP 客戶端請求:
請求過程如下 ⬇️
- 使用者點選或介面自動觸發聯網需求
- Android 程式碼呼叫拼裝 HTTP 報文併傳送請求到服務器
- 服務器處理請求後傳送響應報文給手機
- Android 程式碼處理響應報文並作出相應處理(如儲存資料、加工資料、顯示資料到介面)
1.3 報文是什麼
報文是在 HTTP 應用程式之間傳送的資料塊。這些資料塊以一些文字的元資訊 (meta 標籤中的資訊) 開頭,描述了報文的內容及含義。
每條報文都包含一條來自於客戶端的請求,或者一條來自於服務端的響應。
它由 3 部分組成:對報文進行描述的「起始行」、包含屬性的「首部(Header)」以及可選的、包含資料的「主體(body)」
二、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(請求方法)
最常見的請求方法就是 GET
和 POST
了。除此之外還有 PUT
、DELETE
、HEAD
等。
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
HEAD
與GET
的使用方式完全相同。- 區別在於,
HEAD
請求的返回響應中沒有Body
- 用途:比如下載需求,返回的 Headers 中有下載內容的大小,可以用於顯示進度。
小知識點
GET
、PUT
、DELETE
都是冪等操作,就是說,請求一次和請求多次的結果是一樣的。
比如,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 對應。