HTTP協議(超文本傳輸協議HyperText Transfer Protocol),它是基於TCP協議的應用層傳輸協議,簡單來說就是客戶端和服務端進行數據傳輸的一種規則。
HTTP 最早於 1991 年發布,是 0.9 版,不過目前該版本已不再用。HTTP 目前在使用的版本主要有:
- HTTP/1.0,於 1996 年 5 月發布,引入了多種功能,至今仍在使用當中。
- HTTP/1.1,於 1997 年 1 月發布,持久連接被默認采用,是目前最流行的版本。
- HTTP/2 ,於 2015 年 5 月發布,引入了服務器推送等多種功能,是目前最新的版本。
UPI是由某個協議方案表示的資源定位標識符(協議方案是指訪問資源所使用的協議類型名稱,如http)
URI用字符串標識某一互聯網資源,表示資源地址(在互聯網上所處的位置),URI用於標識各種網絡資源的在網絡中所處的位置(如ftp,http等)。
URL(統一資源定位符)作為web瀏覽器等訪問web頁面時輸入的網頁地址,只標識web頁面資源,所以URL是URI的子集。
URI要使用涵蓋全部必要信息的URI、絕對URL以及相對URL。相對URL是指從瀏覽器中基本URI處理的URL,絕對URI格式:
圖1
應用http協議是,必定是一端擔當客戶端角色,另一端擔當服務器端角色。HTTP協議規定,請求從客戶端發出,最后服務器處理請求並返回響應內容。即先從客戶端開始建立通信的,服務器端在沒有接收到請求之前不會發送響應。
持久鏈接節省通信量
HTTP協議的初始版本中,每進行一次HTTP通信就要斷開一次TCP連接。隨着頁面內容的豐富,一個頁面可能包含多張圖片或其他資源,每次請求都會造成TCP連接的建立和斷開,增加通信量的開銷。為解決該問題,HTTP/1.1及部分HTTP1.0協議規定了HTTP keep-alive持久連接方法。只要任一端沒有明確提出斷開鏈接,則保持TCP連接狀態。
圖2
持久連接的好處在於減少了TCP連接的重復建立和斷開所造成的額外開銷,減輕了服務器端的負載,同時,使得HTTP請求和響應能夠更早的結束,加快了web頁面的響應速度。
管線化
管線化:同時並行發送多個請求。
持久化連接使得多數請求以管線化方式發送成為可能。之前是發送請求后需等待收到響應才發送下一個請求。
使用Cookie 管理狀態
HTTP協議是無狀態的,不對之前發生過的請求和響應的狀態進行管理,即無法根據之前的狀態進行本次的請求處理。比如無法判斷登陸驗證,於是引入Cookie技術,通過在請求和響應報文中添加cookie信息來管理客戶端的狀態。
Cookie會根據服務器發送的響應報文中一個叫Set-Cookie的首部字段信息,通知客戶端保存Cookie值,當下次客戶端再往該瀏覽器發送請求時,客戶端會自動在去請求報文中加入Cookie值再發送。服務器端接收到請求中的Cookie值時,通過對比處理之前的記錄,查出是哪一個客戶端發送過來的狀態信息
HTTP 請求
HTTP 請求由三部分組成:
- 請求行:包含請求方法、請求地址和 HTTP 協議版本
- 消息報頭:包含一系列的鍵值對(請求報頭)
- 請求正文(可選):注意和消息報頭之間有一個空行(請求實體)
如圖所示:
圖3
下面是一個 HTTP GET 請求的例子:
GET /index.html HTTP/1.1Host: httpbin.orgConnection: keep-aliveCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-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.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding: gzip, deflate, sdch, brAccept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4Cookie: _ga=GA1.2.475070272.1480418329; _gat=1復制代碼
請求行:
GET /index.html HTTP/1.1
其中,GET 是請求方法,表示從服務器獲取資源;/index.html 是一個請求地址;HTTP/1.1 表明 HTTP 的版本是 1.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 用於維護狀態,可做用戶認證,服務器檢驗等,它是瀏覽器儲存在用戶電腦上的文本片段;
HTTP 響應
HTTP 響應與 HTTP 請求相似,由三部分組成:
- 狀態行:包含 HTTP 協議版本、狀態碼和狀態描述,以空格分隔
- 響應頭:即消息報頭,包含一系列的鍵值對(響應報頭)
- 響應正文:返回內容,注意和響應頭之間有一個空行(響應主體)
如圖所示:

圖4
下面是一個 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.1200 OK
其中,200 是狀態碼,表示客戶端請求成功,OK 是相應的狀態描述。
狀態行后面的一系列鍵值對就是消息報頭,即響應頭:
Server: nginxDate: Tue, 29 Nov 201613:08:38 GMTContent-Type: application/jsonContent-Length: 203Connection: closeAccess-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 指明本次回應的數據長度;
HTTP 請求方法
HTTP 通過不同的請求方法以多種方式來操作指定的資源,常用的請求方法如下表:
方法
|
描述
|
GET
|
從服務器獲取指定(請求地址)的資源的信息,它通常只用於讀取數據(像數據庫查詢一樣,不會對資源進行修改)
|
POST
|
向指定資源提交數據(比如提交表單,上傳文件),請求服務器進行處理。數據被包含在請求正文中,這個請求可能會創建新的資源或更新現有的資源。
|
PUT
|
通過指定資源的唯一標識(在服務器上的具體存放位置),請求服務器創建或更新資源。
|
DELETE
|
請求服務器刪除指定資源。
|
HEAD
|
與 GET 方法類似,從服務器獲取資源信息,和 GET 方法不同的是,HEAD 不含有呈現數據,僅僅是 HTTP 頭信息。HEAD 的好處在於,使用這個方法可以在不必傳輸全部內容的情況下,就可以獲得資源的元信息(或元數據)。
|
OPTIONS
|
該方法可使服務器傳回資源所支持的所有 HTTP 請求方法。
|
TRACE
|
讓服務器將受到的請求信息回送給客戶端,主要用於測試或診斷,查詢出傳送過程中如何被加工修改(由於容易受到XST跨站追蹤攻擊,一般不用該方法)
|
CONNECT
|
要求在與代理服務器通信時建立隧道,實現用隧道協議進行TCP通信。主要使用SSL(安全套接層)和TLS(傳輸安全)協議把通信內容加密后經網絡隧道傳輸
|
比較 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.1201 CreatedLocation: /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.1201 CreatedLocation: /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 是相同的。
狀態碼:
是一個三位的數字,常見的狀態碼有以下幾類:
- 1XX 消息 -- 請求已被服務接收,正在處理(信息狀態碼)
- 2XX 成功 -- 請求正常處理完畢(成功狀態碼)
- 200 OK
- 201 Created 已創建
- 202 Accepted 接收
- 203 Non-Authoritative Information 非認證信息
- 204 No Content 無內容,表示服務器已成功處理請求,但返回的響應中不包含主體內容(返回204響應,瀏覽器頁面不更新)
- 206 Partial Content 部分內容,表示客戶端進行了范圍請求,服務器成功執行了請求,響應報文中包含了由Content-Range指定范圍的實體內容
- 3XX 重定向 -- 需執行某些特殊處理來正確處理請求(重定向狀態碼)
- 301 Moved Permanently 永久重定向,表示請求的資源已被分配新的URL,希望之后使用新的URL來處理資源
- 302 Moved Temporarily 臨時重定向,表示請求的資源已被分配新的URL,希望之后使用的URL來處理資源,但新分配的URL是臨時的
- 303 See Other 瀏覽其他,表示請求對應地資源處在於另一個URL上,明確表示應該使用get方法獲取資源
- 304 Not Modified 文件未修改,可以直接使用緩存的文件,當客戶端已緩存了目標資源但不確定該緩存資源是否是最新版本時, 就會在請求中附帶條件。 服務器會讀取到附帶條件判斷出客戶端緩存的資源是否最新,如果是的話,服務器就會返回HTTP/304 Not Modified響應頭, 但沒有響應體.客戶端收到304響應后,就會從本地緩存中讀取對應的資源。另一種情況是,如果服務器認為客戶端緩存的資源已經過期了,那么服務器就會返回HTTP/200 OK響應,響應體就是該資源當前最新的內容.客戶端收到200響應后,就會用新的響應體覆蓋掉舊的緩存資源.
- 305 Use Proxy 使用代理
- 307 Temporary Redirect 臨時重定向,表示請求的資源已被分配新的URL,希望之后使用的URL來處理資源,但新分配的URL是臨時的,且禁止Post請求轉換為Get請求。
- 4XX 請求錯誤 -- 請求含有詞法錯誤或者服務器無法處理請求(客戶端錯誤狀態碼),表明錯誤的原因發生在客戶端
- 400 Bad Request 由於客戶端請求有語法錯誤,不能被服務器所理解,需修改內容后重新發送請求
- 401 Unauthorized 請求未經授權,需要有通過HTTP認證的認證信息(若之前已進行過1次請求,則表示用戶認證失敗),同時,返回的401響應中必須包含一個適用於被請求資源的WWW-Authenticate首部來質詢用戶信息(即瀏覽器初次接收到401響應時會彈出認證用的對話窗口)
- 403 Forbidden 服務器收到請求,但是拒絕提供服務。服務器通常會在響應正文中給出不提供服務的原因,比如未獲得文件系統的訪問授權,訪問權限出現問題等
- 404 Not Found 請求的資源不存在,例如,輸入了錯誤的URL,也可以在服務器拒絕請求且不願說明原因時使用
- 5XX 服務器錯誤 -- 服務器處理請求出錯(服務器錯誤狀態碼),表示錯誤的原因發生在服務器端
- 500 Internal Server Error 服務器在執行請求時發生了錯誤。
- 503 Service Unavailable 服務器當前暫時處於超負荷或停機維護狀態,不能夠處理客戶端的請求,在一段時間之后,服務器可能會恢復正常
- 504 Gateway Time-out 網關超時
HTTP 特點
- 客戶端/服務器模式
- 簡單快速:客戶端向服務器請求服務時,通過傳送請求方法、請求地址和數據體(可選)即可
- 靈活:允許傳輸任意類型的數據對象,通過 Content-Type 標識
- 無狀態:對事物處理沒記憶能力
小結
- HTTP 是在網絡上傳輸 HTML 的協議,用於瀏覽器和服務器的通信,默認使用 80 端口。
- URL 地址用於定位資源,HTTP 中的 GET, POST, PUT, DELETE 用於操作資源,比如查詢,增加,更新等。
- GET, PUT, DELETE 是冪等的,POST 是不冪等的。
- POST VS PUT
- 使用 PUT 創建資源需要提供資源的唯一標識(具體存放位置),POST 不需要,POST 的數據存放位置由服務器自己決定
- 使用 PUT 更新某一資源,需要更新資源的全部屬性;而使用 POST,可以更新全部或一部分值
- POST 是不冪等的,PUT 是冪等的,這是一個很重要的區別
- GET 可提交的數據量受到 URL 長度的限制,HTTP 協議規范沒有對 URL 長度進行限制,這個限制是特定的瀏覽器及服務器對它的限制。
- 理論上講,POST 是沒有大小限制的,HTTP 協議規范也沒有進行大小限制,出於安全考慮,服務器軟件在實現時會做一定限制。
參考資料
超文本傳輸協議

