理解HTTP協議

任何一個技術和知識在了解了大概之后還需要在學習和實踐中不斷總結、思考才能真正掌握,變成自己的東西。
用自己的方式分析技術原理,總結自己的經驗,分享他人的見解,轉述權威的解讀。

1 HTTP 協議簡介

HTTP (HyperText Transfer Protocol, 超文本傳輸協議)是互聯網上應用最為廣泛的一種網絡協議,它是基于 TCP 的應用層協議,簡單地說就是客戶端和服務器進行通信的一種規則,它的模式非常簡單,就是客戶端發起請求,服務器響應請求,如下圖所示:

http請求-響應模型

HTTP是一個應用層協議,由請求和響應構成,是一個標準的客戶端服務器模型。HTTP是一個無狀態的協議。
在Internet中所有的傳輸都是通過TCP/IP進行的。HTTP協議作為TCP/IP模型中應用層的協議也不例外。HTTP協議通常承載于TCP協議之上,有時也承載于TLS或SSL協議層之上,這個時候,就成了我們常說的HTTPS。如下圖所示:

111703047392802.png

HTTP默認的端口號為80,HTTPS的端口號為443。
瀏覽網頁是HTTP的主要應用,但是這并不代表HTTP就只能應用于網頁的瀏覽。HTTP是一種協議,只要通信的雙方都遵守這個協議,HTTP就能有用武之地。比如咱們常用的QQ,迅雷這些軟件,都會使用HTTP協議(還包括其他的協議)。

HTTP 最早于 1991 年發布,是 0.9 版,不過目前該版本已不再用。HTTP 目前在使用的版本主要有:

  • HTTP/1.0,于 1996 年 5 月發布,引入了多種功能,至今仍在使用當中。
  • HTTP/1.1,于 1997 年 1 月發布,持久連接被默認采用,是目前最流行的版本。
  • HTTP/2 ,于 2015 年 5 月發布,引入了服務器推送等多種功能,是目前最新的版本。
  • HTTPS,HTTPS是HTTP協議的安全版本,HTTP協議的數據傳輸是明文的,是不安全的,HTTPS使用了SSL/TLS協議進行了加密處理。

2 HTTP工作原理

HTTP協議定義Web客戶端如何從Web服務器請求Web頁面,以及服務器如何把Web頁面傳送給客戶端。HTTP協議采用了請求/響應模型。客戶端向服務器發送一個請求報文,請求報文包含請求的方法、URL、協議版本、請求頭部和請求數據。服務器以一個狀態行作為響應,響應的內容包括協議的版本、成功或者錯誤代碼、服務器信息、響應頭部和響應數據。請求的過程:3次握手,請求,響應,斷開連接。

在TCP協議中要通過三次握手才能建立可靠連接

三次握手

第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,并進入SYN_SEND狀態,等待服務器確認;
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器 進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入 ESTABLISHED狀態,完成三次握手。

UDP和TCP的區別
最本質的區別就是TCP是面向連接的,而UDP是非面向連接的

  • 什么叫面向連接呢?事先為所發送的數據開辟出連接好的通道,然后再進行數據發送,像打電話,只能兩人打,第三人打就顯示占線
  • 非面向連接:是指通信雙方不需要事先建立一條通信線路,而是把每個帶有目的地址的包(報文分組)送到線路上,由系統自主選定路線進行傳輸,就像寫信,不管對方有多忙,把信放到郵筒,就與自己無關系了。

TCP支持的服務有FTP、SMTP等,而UDP支持的服務有DNS、SNMP、QQ等

以下是 HTTP 請求/響應的步驟:

  1. 客戶端連接到Web服務器
    一個HTTP客戶端,通常是瀏覽器,與Web服務器的HTTP端口(默認為80)建立一個TCP套接字連接。例如,https://www.baidu.com

  2. 發送HTTP請求
    通過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成。

  3. 服務器接受請求并返回HTTP響應
    Web服務器解析請求,定位請求資源。服務器將資源復本寫到TCP套接字,由客戶端讀取。一個響應由狀態行、響應頭部、空行和響應數據4部分組成。

  4. 釋放連接TCP連接
    若connection 模式為close,則服務器主動關閉TCP連接,客戶端被動關閉連接,釋放TCP連接;若connection 模式為keepalive,則該連接會保持一段時間,在該時間內可以繼續接收請求;

  5. 客戶端瀏覽器解析HTML內容
    客戶端瀏覽器首先解析狀態行,查看表明請求是否成功的狀態代碼。然后解析每一個響應頭,響應頭告知以下為若干字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,并在瀏覽器窗口中顯示。

例如:在瀏覽器地址欄鍵入URL,按下回車之后會經歷以下流程:

  1. 瀏覽器向 DNS 服務器請求解析該 URL 中的域名所對應的 IP 地址;
  2. 解析出 IP 地址后,根據該 IP 地址和默認端口 80,和服務器建立TCP連接;
  3. 瀏覽器發出讀取文件(URL 中域名后面部分對應的文件)的HTTP 請求,該請求報文作為 TCP 三次握手的第三個報文的數據發送給服務器;
  4. 服務器對瀏覽器請求作出響應,并把對應的 html 文本發送給瀏覽器;
  5. 釋放 TCP連接;
  6. 瀏覽器將該 html 文本并顯示內容;

HTTP協議是基于請求/響應模式的,因此只要服務端給了響應,本次HTTP連接就結束了,或者更準確的說,是本次HTTP請求就結束了,根本沒有長連接這一說。那么自然也就沒有短連接這一說了。
  之所以網絡上說HTTP分為長連接和短連接,其實本質上是說的TCP連接TCP連接是一個雙向的通道,它是可以保持一段時間不關閉的,因此TCP連接才有真正的長連接和短連接這一說。
  其實知道了以后,會覺得這很好理解。HTTP協議說到底是應用層的協議,而TCP才是真正的傳輸層協議,只有負責傳輸的這一層才需要建立連接。

一個形象的例子就是,拿你在網上購物來說,HTTP協議是指的那個快遞單,你寄件的時候填的單子就像是發了一個HTTP請求,等貨物運到地方了,快遞員會根據你發的請求把貨物送給相應的收貨人。而TCP協議就是中間運貨的那個大貨車,也可能是火車或者飛機,但不管是什么,它是負責運輸的,因此必須要有路,不管是地上還是天上。那么這個路就是所謂的TCP連接,也就是一個雙向的數據通道。

因此,LZ現在甚至覺得,“HTTP連接”這個詞就不應該出現,它只是一個應用層的協議,根本就沒有所謂的連接這一說,就像FTP也是應用層的協議,但是你有聽說過FTP連接嗎?(恩,好像是聽過,-_-,但你現在知道了,其實所謂的FTP連接,嚴格來說,依舊是TCP連接)
  實際上,說HTTP請求和HTTP響應會更準確一些,而HTTP請求和HTTP響應,都是通過TCP連接這個通道來回傳輸的。
  不管怎么說,一定要務必記住,長連接是指的TCP連接,而不是HTTP連接

3 HTTPS傳輸協議原理

HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容請看SSL。

3.1 兩種基本的加解密算法類型

  • 對稱加密:密鑰只有一個,加密解密為同一個密碼,且加解密速度快,典型的對稱加密算法有DES、AES等。
  • 非對稱加密:密鑰成對出現(且根據公鑰無法推知私鑰,根據私鑰也無法推知公鑰),加密解密使用不同密鑰(公鑰加密需要私鑰解密,私鑰加密需要公鑰解密),相對對稱加密速度較慢,典型的非對稱加密算法有RSA、DSA等。

3.2 HTTPS通信過程

HTTPS通信過程

3.3 HTTPS通信的優點

客戶端產生的密鑰只有客戶端和服務器端能得到;
加密的數據只有客戶端和服務器端才能得到明文;
客戶端到服務端的通信是安全的。

4 HTTP 請求

請求報文

HTTP 請求由三部分組成:

  • 請求行:包含請求方法、請求地址和 HTTP 協議版本
  • 消息報頭:包含一系列的鍵值對
  • 請求正文(可選):注意和消息報頭之間有一個空行
    如圖所示:
    HTTP請求

下面是一個 HTTP GET 請求的例子:

GET / HTTP/1.1
Host: httpbin.org
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4
Cookie: _ga=GA1.2.475070272.1480418329; _gat=1

上面的第一行就是一個請求行:

GET / HTTP/1.1

其中,GET 是請求方法,表示從服務器獲取資源;/ 是一個請求地址;HTTP/1.1 表明 HTTP 的版本是 1.1。

請求行后面的一系列鍵值對就是消息報頭

Host: httpbin.org
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4
Cookie: _ga=GA1.2.475034215.1480418329; _gat=1

其中:

  • Host 是請求報頭域,用于指定被請求資源的 Internet 主機和端口號,它通常從 HTTP URL 中提取出來;
  • Connection 表示連接狀態,keep-alive 表示該連接是持久連接(persistent connection),即 TCP 連接默認不關閉,可以被多個請求復用,如果客戶端和服務器發現對方有一段時間沒有活動,就可以主動關閉連接;
  • Cache-Control 用于指定緩存指令,它的值有 no-cache, no-store, max-age 等,max-age=秒表示資源在本地緩存多少秒;
  • User-Agent 用于標識請求者的一些信息,比如瀏覽器類型和版本,操作系統等;
  • Accept 用于指定客戶端希望接受哪些類型的信息,比如 text/html, image/gif 等;
  • Accept-Encoding 用于指定可接受的內容編碼;
  • Accept-Language 用于指定可接受的自然語言;
  • Cookie 用于維護狀態,可做用戶認證,服務器檢驗等,它是瀏覽器儲存在用戶電腦上的文本片段;

5 HTTP 請求方法

HTTP請求方法

HTTP 通過不同的請求方法以多種方式來操作指定的資源,常用的請求方法如下表:

方法 描述
GET 從服務器獲取指定(請求地址)的資源的信息,它通常只用于讀取數據,就像數據庫查詢一樣,不會對資源進行修改。
POST 向指定資源提交數據(比如提交表單,上傳文件),請求服務器進行處理。數據被包含在請求正文中,這個請求可能會創建新的資源或更新現有的資源。
PUT 通過指定資源的唯一標識(在服務器上的具體存放位置),請求服務器創建或更新資源
DELETE 請求服務器刪除指定資源。
HEAD 與 GET 方法類似,從服務器獲取資源信息,和 GET 方法不同的是,HEAD 不含有呈現數據,僅僅是 HTTP 頭信息。HEAD 的好處在于,使用這個方法可以在不必傳輸全部內容的情況下,就可以獲得資源的元信息(或元數據)。
OPTIONS 該方法可使服務器傳回資源所支持的所有 HTTP 請求方法。

6 再議 POST 和 PUT

注意到,POST 和 PUT 都可用于創建或更新資源,然而,它們之間還是有比較大的區別:

  • POST 所對應的 URI 并非創建的資源本身,而是資源的接收者,資源本身的存放位置由服務器決定;而 PUT 所對應的 URI 是要創建或更新的資源本身,它指明了具體的存放位置

比如,往某個站點添加一篇文章,如果使用 POST 來創建資源,可類似這樣:

POST /articles HTTP/1.1

{
    "author": "ethan",
    "title": "hello world",
    "content": "hello world"
}

在上面,POST 對應的 URI 是 /articles,它是資源的接收者,而非資源的標識,如果資源被成功創建,服務器可以返回 201 Created 狀態以及新建資源的位置,比如:

HTTP/1.1 201 Created
Location: /articles/abcdef123

我們如果知道新建資源的標識符,可以使用PUT 來創建資源,比如:

PUT /articles/abcdef234 HTTP/1.1

{
    "author": "peter",
    "title": "hello world",
    "content": "hello world"
}

在上面,PUT 對應的 URI 是/articles/abcdef234,它指明了資源的存放位置,如果資源被成功創建,服務器可以返回 201 Created 狀態以及新建資源的位置,比如:

HTTP/1.1 201 Created
Location: /articles/abcdef234
  • 使用 PUT 更新某一資源,需要更新資源的全部屬性;而使用 POST,可以更新全部或一部分值

比如使用 PUT 更新地址為 /articles/abcdef234 的文章的標題,我們需要發送所有值:

PUT /articles/abcdef234 HTTP/1.1

{
    "author": "peter",
    "title": "hello python",
    "content": "hello world"
}

而使用 POST,可以更新某個域的值:

POST /articles/abcdef234 HTTP/1.1

{
    "title": "hello python"
}
  • POST 是不冪等的,PUT 是冪等的,這是一個很重要的區別

HTTP 方法的冪等性是指一次和多次請求某一個資源應該具有同樣的副作用,注意這里是副作用,而不是返回結果。

GET 方法用于獲取資源,不會改變資源的狀態,不論調用一次還是多次都沒有副作用,因此它是冪等的;DELETE 方法用于刪除資源,有副作用,但調用一次或多次都是刪除同個資源,產生的副作用是相同的,因此也是冪等的;POST 是不冪等的,因為兩次相同的 POST 請求會在服務器創建兩份資源,它們具有不同的 URI;PUT 是冪等的,對同一 URI 進行多次 PUT 的副作用和一次 PUT 是相同的。

7 HTTP 響應

響應報文

HTTP 響應與 HTTP 請求相似,由三部分組成:

  • 狀態行:包含 HTTP 協議版本、狀態碼和狀態描述,以空格分隔
  • 響應頭:即消息報頭,包含一系列的鍵值對
  • 響應正文:返回內容,注意和響應頭之間有一個空行
    如圖所示:


    HTTP響應

下面是一個 HTTP GET 請求的響應結果:

HTTP/1.1 200 OK
Server: nginx
Date: Tue, 29 Nov 2016 13:08:38 GMT
Content-Type: application/json
Content-Length: 203
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "args": {}, 
  "headers": {
    "Host": "httpbin.org", 
    "User-Agent": "Paw/2.3.1 (Macintosh; OS X/10.11.3) GCDHTTPRequest"
  }, 
  "origin": "13.75.42.240", 
  "url": "https://httpbin.org/get"
}

上面的第一行就是一個狀態行:

HTTP/1.1 200 OK

其中,200 是狀態碼,表示客戶端請求成功,OK 是相應的狀態描述。

狀態碼是一個三位的數字,常見的狀態碼有以下幾類:

HTTP的響應狀態碼

1XX 消息 -- 請求已被服務接收,繼續處理
2XX 成功 -- 請求已成功被服務器接收、理解、并接受
200 OK
201 Created 已創建
202 Accepted 接收
203 Non-Authoritative Information 非認證信息
204 No Content 無內容
3XX 重定向 -- 需要后續操作才能完成這一請求
301 Moved Permanently 請求永久重定向
302 Moved Temporarily 請求臨時重定向
304 Not Modified 文件未修改,可以直接使用緩存的文件
305 Use Proxy 使用代理
4XX 請求錯誤 -- 請求含有詞法錯誤或者無法被執行
400 Bad Request 由于客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthorized 請求未經授權。這個狀態代碼必須和WWW-Authenticate報頭域一起使用
403 Forbidden 服務器收到請求,但是拒絕提供服務。服務器通常會在響應正文中給出不提供服務的原因
404 Not Found 請求的資源不存在,例如,輸入了錯誤的URL
5XX 服務器錯誤 -- 服務器在處理某個正確請求時發生錯誤
500 Internal Server Error 服務器發生不可預期的錯誤,導致無法完成客戶端的請求
503 Service Unavailable 服務器當前不能夠處理客戶端的請求,在一段時間之后,服務器可能會恢復正常
504 Gateway Time-out 網關超時

狀態行后面的一系列鍵值對就是消息報頭,即響應頭:

Server: nginx
Date: Tue, 29 Nov 2016 13:08:38 GMT
Content-Type: application/json
Content-Length: 203
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

其中:

  • Server 包含了服務器用來處理請求的軟件信息,跟請求報頭域 User-Agent 相對應;
  • Content-Type 用于指定發送給接收者(比如瀏覽器)的響應正文的媒體類型,比如 text/html, text/css, image/png, image/jpeg, video/mp4, application/pdf, application/json 等;
  • Content-Length 指明本次回應的數據長度;

8 HTTP 特點

  • 客戶端/服務器模式
  • 簡單快速:客戶端向服務器請求服務時,通過傳送請求方法、請求地址和數據體(可選)即可
  • 靈活:允許傳輸任意類型的數據對象,通過 Content-Type 標識
  • 無狀態:對事物處理沒記憶能力,HTTP協議是無狀態的,就是說每次HTTP請求都是獨立的,任何兩個請求之間沒有什么必然的聯系。但是在實際應用當中并不是完全這樣的,引入了Cookie和Session機制來關聯請求。
  • 多次HTTP請求,在客戶端請求網頁時多數情況下并不是一次請求就能成功的,服務端首先是響應HTML頁面,然后瀏覽器收到響應之后發現HTML頁面還引用了其他的資源,例如,CSS,JS文件,圖片等等,還會自動發送HTTP請求這些需要的資源。現在的HTTP版本支持管道機制,可以同時請求和響應多個請求,大大提高了效率。
  • 基于TCP協議,HTTP協議目的是規定客戶端和服務端數據傳輸的格式和數據交互行為,并不負責數據傳輸的細節。底層是基于TCP實現的。現在使用的版本當中是默認持久連接的,也就是多次HTTP請求使用一個TCP連接。

9 Cookie和Session的區別和聯系

Cookie和Session都是為了保存客戶端和服務端之間的交互狀態,實現機制不同,各有優缺點。首先一個最大的區別就是Cookie是保存在客戶端而Session就保存在服務端的。Cookie是客戶端請求服務端時服務器會將一些信息以鍵值對的形式返回給客戶端,保存在瀏覽器中,交互的時候可以加上這些Cookie值。用Cookie就可以方便的做一些緩存。Cookie的缺點是大小和數量都有限制;Cookie是存在客戶端的可能被禁用、刪除、篡改,是不安全的;Cookie如果很大,每次要請求都要帶上,這樣就影響了傳輸效率。Session是基于Cookie來實現的,不同的是Session本身存在于服務端,但是每次傳輸的時候不會傳輸數據,只是把代表一個客戶端的唯一ID(通常是JSESSIONID)寫在客戶端的Cookie中,這樣每次傳輸這個ID就可以了。Session的優勢就是傳輸數據量小,比較安全。但是Session也有缺點,就是如果Session不做特殊的處理容易失效、過期、丟失或者Session過多導致服務器內存溢出,并且要實現一個穩定可用安全的分布式Session框架也是有一定復雜度的。在實際使用中就要結合Cookie和Session的優缺點針對不同的問題來設計解決方案。

10 小結

  • HTTP 是在網絡上傳輸 HTML 的協議,用于瀏覽器和服務器的通信,默認使用 80 端口。
  • URL 地址用于定位資源,HTTP 中的 GET, POST, PUT, DELETE 用于操作資源,比如查詢,增加,更新等。
  • GET, PUT, DELETE 是冪等的,POST 是不冪等的
  • POST VS PUT
  1. 使用 PUT 創建資源需要提供資源的唯一標識(具體存放位置),POST 不需要,POST 的數據存放位置由服務器自己決定
  2. 使用 PUT 更新某一資源,需要更新資源的全部屬性;而使用 POST,可以更新全部或一部分值
  3. POST 是不冪等的,PUT 是冪等的,這是一個很重要的區別
  • GET 可提交的數據量受到URL 長度的限制,HTTP 協議規范沒有對 URL 長度進行限制,這個限制是特定的瀏覽器及服務器對它的限制。

每種瀏覽器也會對url的長度有所限制,下面是幾種常見瀏覽器的url長度限制:(單位:字符)

  IE  :  2803ASCII字符
  Firefox  :  65536ASCII字符 
  Chrome  :  8182ASCII字符
  Safari  :  80000ASCII字符
  Opera  :  190000ASCII字符

對于get請求,在url的長度限制范圍之內,請求的參數個數沒有限制。

  • 理論上講,POST 是沒有大小限制的,HTTP 協議規范也沒有進行大小限制,出于安全考慮,服務器軟件在實現時會做一定限制。

編程并沒有捷徑,真正的成長都是來源于實踐、思考和總結。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容