不忘初心 砥礪前行, Tomorrow Is Another Day !
本文概要:
- TCP/IP協議族的網路分層
- TCP三次握手四次揮手
- Http簡介
- 報文結構
- Http的請求方法及狀態碼
- 常用的Header
前言:
宣告:掌握好HTTP非常重要,具體理由本文最後再揭曉!
一. TCP/IP協議族的網路分層
在瞭解HTTP協議之前,先來快速瞭解TCP/IP的網路分層以及三次握手四次揮手的流程.
1.1 網路分層
由於網路的不穩定性,所以將網路分層多個網路模型.
- 應用層: HTTP FTP DNS
- 傳輸層: TCP UDP
- 網路層: IP
- 鏈路層: 乙太網 WIFI
大致流程:
- 應用層將內容打包好交給傳輸層.
- 傳輸層負責將內容資訊進行切割分包,依次交給網路層.並確認資訊是否傳送成功.
- 如果不成功,將資料包繼續交給網路層傳送.
- 網路層只負責將資訊的傳送到目標地址,不負責資訊全部準確傳送到目標地址.
- 確認資訊是否傳送成功的是傳輸層.
- 最後實際傳送的是通過我們的鏈路層也就是網線和閘道器路由等.
1.2 TCP三次握手四次揮手
這裡用最簡單粗暴的方式快速瞭解其過程,不帶任何複雜的專業術語.讓你看圖就明白.
- 三次握手
- 四次揮手
可以發現在四次揮手中,第2步與第3步會分開傳送,之所以這樣是因為此時伺服器可能還有訊息沒有傳送完畢.所以就沒有像握手流程時一起傳送訊息.
二. Http簡介
HyperText Transfer Protocol 超文字傳輸協議
- URL 格式 : 協議型別 + 主機名 + 路徑
示例
- http : 協議型別
- api.github.com : 主機名
- /users?key1=value1&key2=value2 : 路徑
三. 報文結構
- 請求報文結構
示例
GET /users HTTP/1.1
Host: api.github.com
Content-Type: text/html
Content-Length: 110
bodybodybody假裝我是一個Body
bodybodybodybodybodybody
複製程式碼
- 響應報文結構
響應報文和請求報文大同小異,只是將請求行換成了狀態行.
示例
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
cache-control: public, max-age=60, s-maxage=60
content-encoding: gzip
bodybodybody假裝我是一個Body
bodybodybodybodybodybody
複製程式碼
四. 請求方式及狀態碼
4.1 狀態碼
status code | 類別 | 原因短語 | 示例 |
---|---|---|---|
1XX | Informational(臨時資訊) | 接收的請求正在處理 | 100(繼續傳送) |
2XX | Success | 請求正常處理完畢 | 200(OK) |
3XX | Redirection(重定向) | 需要進行附加操作以完成請求 | 301(永久移動)、304(內容未改變) |
4XX | Client Error | 伺服器無法處理請求 | 400(客戶端請求錯誤)、404(內容找不到) |
5XX | Server Error | 伺服器處理請求出錯 | 500(伺服器內部錯誤) |
更多資訊,可以檢視HTTP狀態碼詳解
4.2 請求方式
Method | description |
---|---|
GET | 1. 獲取資源 2. 不傳送Body |
POST | 1. 增加或者修改資源 2. 傳送Body |
PUT | 1.修改資源 2. 傳送Body |
DELETE | 1.刪除資源 2. 不傳送Body |
HEAD | 與GET基本一致 , 區別在於返回響應無Body |
五. 常見的Header
HTTP的後設資料,傳遞一些附加資訊.
格式: 鍵: 值,注意冒號後面有一個空格!
由於Header過多,這裡只列舉了個人覺得比較重要且常用的Header
5.1 通用的Header
欄位名 | 內容說明 |
---|---|
Content-Type | 內容型別(下一節詳細講解) |
Content-Length | 內容長度,單位位元組 |
Content-Encoding | 壓縮編碼格式,如gzip |
Last-Modified | 資源的最後修改日期時間 |
Cache-Control | 控制快取的行為,取值為一般為no-cache或max-age=XX |
5.2 請求Header
欄位名 | 內容說明 |
---|---|
Host | 請求的主機和埠號 |
User-Agent | 使用者代理,僅用於找到目標主機後確認主機域名和埠 |
Accept | 接受的媒體型別,可以多個值,用,(半形逗號)分開.如text/html, |
Accept-Charset | 接受的字符集,如UTF-8 |
Accept-Encoding | 接受的壓縮編碼型別,如gzip |
--- | ------------------------------------------ |
Last-Modified | 值,用於確認某個資源是否被更改過,沒有更改過(304)就從快取中讀取 |
If-Modified-Since | 比較資源的更新時間;值為上一次伺服器返回的 |
If-Match | 比較實體標記(ETag) |
If-None-Match | 比較實體標記(與 If-Match 相反);值為上一次伺服器返回的 ETag 值,一般會和If-Modified-Since一起出現 |
--- | ------------------------------------------ |
Cookie | 已有的Cookie |
Authorization | 用於設定身份認證資訊 |
5.3 響應Header
欄位名 | 內容說明 |
---|---|
Location | 令客戶端重定向至指定URI |
Transfer-Encoding | 分塊傳輸,如Transfer-Encoding: chunked |
Accept-Range | 如Accept-Range: bytes,表示伺服器支援按位元組獲取資料 |
Content-Range | 如Content-Range:-/total,表示傳送的是哪段資料 |
----------- | ------------------------------ |
ETag | 資源的匹配標識,和Last-Modified、If-None-Match、If-Modified-Since配合,用於快取控制 |
Set-Cookie | 設定Cookie |
最後著重學習下Content-Type,這是實際開發中最經常使用的.
- Content-Type
指定Body的型別
- text/html 一般用於響應時,返回html頁面.
示例
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
Content-Length: 666
<!DOCTYPE html>
<html>
<head>
......
</head>
<body>
......
<body>
</html>
複製程式碼
- application/x-www-form-urlencoded
普通表單,提交純文字.
示例
POST /users HTTP/1.1
Host: api.github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
userName=jasonhww&password=123456
複製程式碼
對應Retrofit程式碼
@FormUrlEncoded
@POST("/users")
Observable<User> login(@Field("userName") String userName, @Field("password") String
password);
複製程式碼
- multipart/form-data; boundary={boundary} 帶檔案的表單
將body分成多個部分,每部分都被boundary分成單獨的段;
- 每段以 -- 加 boundary開頭,
- 然後是該段的conten-disposition,
- 空行,
- 傳入的value,
- 最後請求結束的標識為boundary後面加--
示例
POST /users/photo HTTP/1.1
Host: api.github.com
Content-Length: 3698
請求頭 Content-Type: multipart/form-data;boundary={boundary的值}
空行
請求體part1 --{boundary的值}
conten-disposition: form-data; name="userName"
\r\n
jasonhww
請求體part2 --{boundary的值}
conten-disposition: form-data; pwd="password"
\r\n
123456
請求體part3 --{boundary的值}
conten-disposition: form-data; name="photo"; filename="檔名.txt";
Content-Type: image/jpeg
\r\n
sdsdsdfqfvfvsvadvavdavakvkakvadvanvnav
afdfafaiewfre482ekdsji21dnefrgoonwncvewnfefeowkkr假設我是一個檔案ddsrrogkrn2n3934
請求體結束 ---boundary的值--
複製程式碼
其中Content-Disposition中的filename是區分是否當成檔案;因為檔案有不同的型別,所以還要使用Content-Type指示檔案的型別;如果不知道是什麼型別取值可以為application/octet-stream表示該檔案是個二進位制檔案.
對應Retrofit程式碼
@Multipart
@POST("/users/photo")
Observable<User> uploadPhoto(@Part("userName") RequestBody userName, @Part("password") RequestBody password, @Part("photo")
RequestBody photo);
RequestBody namePart = RequestBody.create(MediaType.parse("text/plain"),
nameStr);
RequestBody pwdPart = RequestBody.create(MediaType.parse("text/plain"),
nameStr);
RequestBody avatarPart = RequestBody.create(MediaType.parse("image/jpeg"),
avatarFile);
api.addUser(namePart, avatarPart);
複製程式碼
- application/json , image/jpeg
單內容,實際開發使用較少.
示例-提交json
POST /users HTTP/1.1
Host: api.github.com
Content-Type: application/json
Content-Length: 41
{"userName":"jasonhww","password":123456}
複製程式碼
這樣請求body中直接為json字串了
對應Retrofit程式碼
@POST("/users")
Observable<User> addUser(@Body("user") User user);
複製程式碼
示例-提交檔案
POST /users/photo HTTP/1.1
Host: api.github.com
Content-Type: image/jpeg
Content-Length: 6666
dsfdsfncwowncnowncodwcw...假設是個檔案資料
複製程式碼
這樣請求body中直接為檔案資料了
對應Retrofit程式碼
@POST("/users/photo")
Observable<User> updatePhoto(@Body RequestBody avatar);
複製程式碼
最後順便提下restFul,其實 RestFul風格就是指規範的使用HTTP,但是國內大多數公司一般都不遵從.比如請求方式,實際就只會用到GET與POST.
另外:前面提到掌握好HTTP非常重要,現在揭曉理由,理由就是除錯介面時,與後臺互懟的強力保障,再也不要擔心他們忽悠客戶端了.O(∩_∩)O
不過新時代社會主義還是和諧為主,儘量少互懟,合作共贏才是正道!
由於本人技術有限,如有錯誤的地方,麻煩大家給我提出來,本人不勝感激,大家一起學習進步.
參考連結: