[http協議入門:https://www.ruanyifeng.com/blog/2016/08/http.html]([https://www.ruanyifeng.com/blog/2016/08/http.html](https://www.ruanyifeng.com/blog/2016/08/http.html))
## HTTP工作原理
HTTP協議定義Web客戶端如何從Web服務器請求Web頁面,以及服務器如何把Web頁面傳送給客戶端。HTTP協議采用了請求/響應模型。客戶端向服務器發送一個請求報文,請求報文包含請求的方法、URL、協議版本、請求頭部和請求數據。服務器以一個狀態行作為響應,響應的內容包括協議的版本、成功或者錯誤代碼、服務器信息、響應頭部和響應數據。
1. **客戶端連接到Web服務器**
一個HTTP客戶端,通常是瀏覽器,與Web服務器的HTTP端口(默認為80)建立一個TCP套接字連接
2. **發送HTTP請求**
通過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成
3. **服務器接受請求并返回HTTP響應**
Web服務器解析請求,定位請求資源。服務器將資源復本寫到TCP套接字,由客戶端讀取。一個響應由狀態行、響應頭部、空行和響應數據4部分組成。
4. **釋放連接 TCP連接**
若connection 模式為close,則服務器主動關閉[TCP連接](https://www.jianshu.com/p/ef892323e68f),客戶端被動關閉連接,釋放[TCP連接](https://www.jianshu.com/p/ef892323e68f);若connection 模式為keepalive,則該連接會保持一段時間,在該時間內可以繼續接收請求;
5. **客戶端瀏覽器解析HTML內容**
客戶端瀏覽器首先解析狀態行,查看表明請求是否成功的狀態代碼。然后解析每一個響應頭,響應頭告知以下為若干字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,并在瀏覽器窗口中顯示。
## HTTP響應頭的 Content-Type字段
頭信息必須是ASCII碼,數據部分可以是任何格式。因此,服務器回應的時候,必須告訴客戶端,數據是什么格式的,這就是Content-Type字段的作用。如`text/html`,`text/css`,`application/javascript`等
客戶端請求的時候,可以使用Accept字段聲明自己可以接受哪些數據格式`Accept:*/*`;
## Content-Encoding字段
由于發送的數據可以是任何格式,因此可以把數據壓縮后再發送。Content-Encoding字段說明數據的壓縮方法
```
Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate
```
客戶端在請求時,用Accept-Encoding字段說明自己可以接受哪些壓縮方法。`Accept-Encoding: gizp, deflate;`
## 持久連接
HTTP1.1引入了持久連接,即TCP連接默認不關閉,可以被多個請求復用,不用聲明`Connection:keep-alive`.
客戶端和服務器發現對方一段時間沒有活動,就可以主動關閉連接。不過規范的做法是,客戶端在最后一個請求時,發送`Connection: close`,明確要求服務器關閉TCP連接
## 管道機制
1.1 版還引入了管道機制(pipelining),即在同一個TCP連接里面,客戶端可以同時發送多個請求。這樣就進一步改進了HTTP協議的效率
舉例來說,客戶端需要請求兩個資源。以前的做法是,在同一個TCP連接里面,先發送A請求,然后等待服務器做出回應,收到后再發出B請求。管道機制則是允許瀏覽器同時發出A請求和B請求,但是服務器還是按照順序,先回應A請求,完成后再回應B請求。
## Content-Length字段
一個TCP連接現在可以傳送多個回應,勢必就要有一種機制,區分數據包是屬于哪一個回應的。這就是`Content-length`字段的作用,聲明本次回應的數據長度。
```
Content-Length: 3495
```
上面代碼告訴瀏覽器,本次回應的長度是3495個字節,后面的字節就屬于下一個回應了。
在1.0版中,`Content-Length`字段不是必需的,因為瀏覽器發現服務器關閉了TCP連接,就表明收到的數據包已經全了。
## 分塊傳輸編碼
使用`Content-Length`字段的前提條件是,服務器發送回應之前,必須知道回應的數據長度。
對于一些很耗時的動態操作來說,這意味著,服務器要等到所有操作完成,才能發送數據,顯然這樣的效率不高。更好的處理方法是,產生一塊數據,就發送一塊,采用"流模式"(stream)取代"緩存模式"(buffer)。
因此,1.1版規定可以不使用`Content-Length`字段,而使用"分塊傳輸編碼"(chunked transfer encoding)。只要請求或回應的頭信息有`Transfer-Encoding`字段,就表明回應將由數量未定的數據塊組成。
每個非空的數據塊之前,會有一個16進制的數值,表示這個塊的長度。最后是一個大小為0的塊,就表示本次回應的數據發送完了