關於HTTP請求你需要知道的一切
前言
現在幾乎所有的客戶端(不管是APP也好,H5頁面也好),都需要用到網路請求,而絕大多數公司都會把客戶端的網路框架封裝好,我們直接拿來用就好了,不用管什麼原理,只要請求以後能得到正確的返回就可以了,但如果讓你從零開始封裝一個請求框架,或者你接到了一個別的專案,當前的網路請求框架不合適或者不好用了,這時候你可能就懵了。本文將會講述請求(Request)和響應(Response)的完整組成部分、Header的關鍵引數、HTTP 狀態碼的含義以及如何封裝自己的請求框架。
HTTP Request請求報文
先上個圖

請求報文 Request
分為三個部分:請求行、Headers和Body。
請求行:又分為三個部分method(下面會詳細講)、path(給伺服器看得,如何你會一些後臺的知識你會明白這其實就是來找後臺的響應方法的)和HTTP version(當前大多數都是1.1,當然2.0會是趨勢)
Headers:headers上的資訊可以有很多,不止是圖中列的這些,比較重點是Content-Type(下面會詳細講,現在知道是指body的型別就可以),還有很多自己公司後臺定義的引數比如token、stamptime等等。
Body:首先body不是一定存在的,這需要根據你請求行裡的方法決定,如果是POST或者PUT那麼body一定存在;如果是GET或者DELETE那麼則沒有body,body的型別剛才也提了由headers裡面的Content-Type決定。
注意:
以上就是一個完整的Request的組成部分,這裡還需要再提一下URL,一個完整的URL組成部分: 協議型別 、 伺服器地址 和 路徑 。那麼根據上圖的資訊,請求的完整URL就是: ofollow,noindex">http://api.github.com/users
下面我用Retrofit為例,模擬一下上面的請求
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://api.github.com") .build(); @Headers("Content-Type:text/plain") @POST("/users") Call<User> getUser(@Field("username")String name,@Field("pwd")String pwd); retrofit.create(KakaService.class).getUser("kaka","123456");
這一段程式碼發給服務端過後就會變成上面HTTP Request請求報文,這下關於Request請求的組成應該都明白了吧
HTTP Response響應報文
再上個圖

Response響應報文
同樣分為三個部分:狀態行、Headers和Body
狀態行:三個部分,HTTP version、status code和status message。status 是狀態碼,對請求結果做描述的,下面會詳細講。
Headers:響應返回的頭資訊,其中比較常見的是Content-Type、Content-Length和Cache-Control等等,響應返回的headers包含的引數很多,這裡只舉了一小部分,想看更多的可以使用 POSTMAN 請求一下。
Body:這是我們開發者最最關心的內容,來自伺服器的相應資訊。返回內容現在一般都是json了(不過還是有一些公司返回的xml),通過json相關的解析工具轉成我們想要的資料。
Request 請求Method
GET
⽤於獲取資源
對伺服器資料不進⾏修改
不傳送 Body
HTTP請求報文 GET /users/1 HTTP/1.1 Host: api.github.com
//程式碼展示 @GET("/users/{id}") Call<User> getUser(@Path("id") String id);
POST
⽤於增加或修改資源
傳送給伺服器的內容寫在 Body ⾥⾯
HTTP 請求報文 POST /users HTTP/1.1 Host: api.github.com Content-Type: application/x-www-form-urlencoded Content-Length: 13 username=kaka&pwd=123456
程式碼展示 @FormUrlEncoded @POST("/users") Call<User> addUser(@Field("username") String username, @Field("pwd") String pwd)
PUT
⽤於修改資源
傳送給伺服器的內容寫在 Body ⾥⾯
HTTP 請求報文 PUT /users/1 HTTP/1.1 Host: api.github.com Content-Type: application/x-www-form-urlencoded Content-Length: 13 pwd=654321
程式碼展示 @FormUrlEncoded @PUT("/users/{id}") Call<User> updateGender(@Path("id") String id, @Field("pwd") String pwd);
DELETE
⽤於刪除資源
不傳送 Body
HTTP 請求報文 DELETE /users/1 HTTP/1.1 Host: api.github.com
@DELETE("/users/{id}") Call<User> getUser(@Path("id") String id);
HEAD
和 GET 使⽤⽅法完全相同
和 GET 唯⼀區別在於,返回的響應中沒有 Body
一般用在多執行緒下載的時候,header裡面返回Range / Accept-Range裡的資料可以判斷下載範圍
注意:
本文只講一些常用的重點方法,像HEAD、PATCH等方法不講可以自行百度。
Header ⾸部
Content-Type
指定 Body 的型別。主要有四類:
-
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=kaka&pwd=123456
-
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......對應 Retrofit 的程式碼: 4. application/json , image/jpeg , application/zip ... 單項內容(⽂本或⾮⽂本都可以),⽤於 Web Api 的響應或者 POST / PUT 的請求 請求中提交 JSON 對應 Retrofit 的程式碼: 響應中返回 JSON ------WebKitFormBoundary7MA4YWxkTrZu0gW
-
application/json , image/jpeg , application/zip ...
單項內容(⽂本或⾮⽂本都可以),⽤於 Web Api 的響應或者 POST / PUT 的請求
注意:header裡面的這個content-type還是非常重要的,這決定於你和後臺商量好的請求格式,以上的這些請牢記!
Content-Length
指定 Body 的⻓度(位元組)
Location
指定重定向的⽬標 URL
User-Agent
⽤戶代理,即是誰實際傳送請求、接受響應的,例如⼿機瀏覽器、某款⼿機 App。
Range / Accept-Range
按範圍取資料
Accept-Range: bytes 響應報⽂中出現,表示伺服器⽀持按位元組來取範圍資料
Range: bytes=<start>-<end> 請求報⽂中出現,表示要取哪段資料
Content-Range:<start>-<end>/total 響應報⽂中出現,表示傳送的是哪段資料
作⽤:斷點續傳、多執行緒下載。
其他 Headers
Accept: 客戶端能接受的資料型別。如 text/html
Accept-Charset: 客戶端接受的字符集。如 utf-8
Accept-Encoding: 客戶端接受的壓縮編碼型別。如 gzip
Content-Encoding:壓縮型別。如 gzip
Status Code 狀態碼
三位數字,⽤於對響應結果做出型別化描述(如「獲取成功」「內容未找到」)。
1xx:臨時性訊息。如: 100 (繼續傳送)、 101(正在切換協議)
2xx:成功。最典型的是 200( OK)、 201(建立成功)。
3xx:重定向。如 301(永久移動)、 302(暫時移動)、 304(內容未改變)。
4xx:客戶端錯誤。如 400(客戶端請求錯誤)、 401(認證失敗)、 403(被禁⽌)、 404(找不到內容)。
5xx:伺服器錯誤。如 500(伺服器內部錯誤)
注意:為什麼會有status code?status code的出現是為了開發者除錯的,其中200我們最喜歡也最常見,返回正常,一切OK。其中最主要記得分清楚4XX和5XX的區別,但凡是4XX的這種移動端的同事就不要找後臺的麻煩,指定是客戶端的問題了,1XX臨時性訊息一般是迅雷多執行緒下載會返回的,3XX是重定向,一般用的比較少。
如何封裝自己的網路框架
其實,我相信你只要認真學習了上面的知識,封裝自己的網路請求框架應該不是什麼問題了,下面我們就來總結一下,都需要注意封裝是什麼:
1. headers :這個是必須要注意的,因為現在的網路請求越來越注意安全性,有一些中小型的創業公司為了資訊保安,經常在headers傳一系列的加密資訊,因為對headers的封裝是必不可少的
2. body :body裡面的內容封裝主要取決於headers裡的Content-type,根據不同的Content-type生成不同的body可以讓我們的網路框架使用更加方便。
3. status code :對status code的封裝是方便當我們網路發生錯誤時,給我們開發者更快地定位問題所在。
最後給大家提供一個我自己封裝的例子,用的是當前比較流行的Retrofit+RxJava, https://www.jianshu.com/p/b5546905ccbc