HTTP 是基於 TCP/IP 協議的應用層協議。它不涉及數據包(packet)傳輸,主要規定了客戶端和服務器之間的通訊格式,默認使用80端口。javascript
最先版本是1991年發佈的0.9版。該版本極其簡單,只有一個命令GET,而且協議規定,服務器只能迴應HTML格式的字符串,不能迴應別的格式,服務器發送完畢,就關閉TCP鏈接。html
1996年5月,HTTP/1.0 版本發佈,內容大大增長。 首先,任何格式的內容均可以發送,其次,除了GET命令,還引入了POST命令和HADE命令,豐富了瀏覽器與服務器的互動手段。 再次,HTTP請求和迴應的格式也變了。除了數據部分,每次通訊都必須包括頭信息(HTTP header
),用來描述一些元數據。 其餘的新增功能還包括狀態碼(status code
)、多字符集支持、多部分發送(multi-part type
)、權限(authorization
)、緩存(cache
)、內容編碼(content encoding
)等。java
第一行是請求命令,必須在尾部添加協議版本(HTTP/1.0)。後面就是多行信息,描述客戶端的狀況。算法
例如:瀏覽器
GET / HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
複製代碼
迴應的格式是「頭信息+一個空行+數據」。其中,第一行是「協議版本+狀態碼+狀態描述」。緩存
例如;安全
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
<html>
<body>Hello World</body>
</html>
複製代碼
Content-Type字段bash
關於字符編碼,該版本要求頭信息必須是ASII碼,後面的數據能夠是任何格式。服務器
做用:告訴客戶端數據是什麼格式。網絡
經常使用的Content-Type
字段
text/html
image/png
application/javascript
application/pdf
application/zip
複製代碼
客戶端請求的時候,可使用Accept字段聲明本身能夠接受哪些數據格式。
這些數據類型總稱爲MIME type
,每個值包括一級類型和二級類型,之間用斜槓分割。MIME type
不只用在HTTP協議,還能夠用在其餘地方,好比HTML網頁中。
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- 等同於 -->
<meta charset="utf-8" />
複製代碼
Content-Encoding 字段 因爲發送的數據可使任何格式,所以能夠把數據壓縮後在發送。Content-Encoding
字段說明數據的壓縮方式。
客戶端在請求時,用Accept-Encoding字段說明本身能夠接受哪些壓縮方法。
HTTP/1.0 版本的主要缺點是:每一個TCP鏈接只能是發送一個請求。發送完數據以後,鏈接就關閉,若是還要請求其餘資源,就必須再新建一個鏈接。
TCP鏈接的新建成本很高,由於須要客戶端和服務器三次握手,而且開始時發送速率較慢(slow start)。因此,HTTP 1.0版本的性能比較差。
爲了解決這個問題,有些瀏覽器在請求時,用了一個非標準的Connection字段。
Connection: keep-alive
複製代碼
這個字段要求服務器不要關閉TCP鏈接,以便其餘請求複用。服務器一樣迴應這個字段。
Connection: keep-alive
複製代碼
一個能夠複用的TCP鏈接就創建了,直到客戶端或服務器主動關閉鏈接。可是,這不是標準字段,不一樣實現的行爲可能不一致,所以不是根本的解決辦法。
1997年1月,HTTP/1.1 版本發佈,它進一步完善了 HTTP 協議。
1.1 版的最大變化,就是引入了持久鏈接(persistent connection
),即TCP鏈接默認不關閉,能夠被多個請求複用,不用聲明Connection: keep-alive
。
客戶端和服務器發現對方一段時間沒有活動,就能夠主動關閉鏈接。不過,規範的作法是,客戶端在最後一個請求時,發送Connection: close
,明確要求服務器關閉TCP鏈接。
Connection: close
複製代碼
目前,對於同一個域名,大多數瀏覽器容許同時創建6個持久鏈接。
1.1 版還引入了管道機制(pipelining
),即在同一個TCP鏈接裏面,客戶端能夠同時發送多個請求。這樣就進一步改進了HTTP協議的效率。
舉例來講,客戶端須要請求兩個資源。之前的作法是,在同一個TCP鏈接裏面,先發送A請求,而後等待服務器作出迴應,收到後再發出B請求。管道機制則是容許瀏覽器同時發出A請求和B請求,可是服務器仍是按照順序,先回應A請求,完成後再回應B請求。
一個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
字段,就代表迴應將由數量未定的數據塊組成。
Transfer-Encoding: chunked
複製代碼
1.1版還新增了許多動詞方法:PUT
、PATCH
、HEAD
、 OPTIONS
、DELETE
。
另外,客戶端請求的頭信息新增了Host字段,用來指定服務器的域名。
Host: www.example.com
複製代碼
有了Host字段,就能夠將請求發往同一臺服務器上的不一樣網站,爲虛擬主機的興起打下了基礎。
雖然服用了TCP鏈接,可是在同一個TCP鏈接中,全部的數據通訊時按次序進行的。服務器只能處理完一個迴應,纔會進行下一個迴應。要是前面的迴應特別慢,後面就會有許多請求排隊等着。這稱爲"隊頭堵塞"。
2015年,HTTP/2 發佈。它不叫 HTTP/2.0,是由於標準委員會不打算再發布子版本了,下一個新版本將是 HTTP/3。
HTTP/1.1 版的頭信息確定是文本(ASCII編碼),數據體能夠是文本,也能夠是二進制。HTTP/2 則是一個完全的二進制協議,頭信息和數據體都是二進制,而且統稱爲"幀"(frame
):頭信息幀和數據幀。
二進制協議的一個好處是,能夠定義額外的幀。HTTP/2 定義了近十種幀,爲未來的高級應用打好了基礎。若是使用文本實現這種功能,解析數據將會變得很是麻煩,二進制解析則方便得多。
HTTP/2 複用TCP鏈接,在一個鏈接裏,客戶端和瀏覽器均可以同時發送多個請求或迴應,並且不用按照順序一一對應,這樣就避免了"隊頭堵塞"。
舉例來講,在一個TCP鏈接裏面,服務器同時收到了A請求和B請求,因而先回應A請求,結果發現處理過程很是耗時,因而就發送A請求已經處理好的部分, 接着迴應B請求,完成後,再發送A請求剩下的部分。
這樣雙向的、實時的通訊,就叫作多工(Multiplexing
)。
由於 HTTP/2 的數據包是不按順序發送的,同一個鏈接裏面連續的數據包,可能屬於不一樣的迴應。所以,必需要對數據包作標記,指出它屬於哪一個迴應。
HTTP/2 將每一個請求或迴應的全部數據包,稱爲一個數據流(stream
)。每一個數據流都有一個獨一無二的編號。數據包發送的時候,都必須標記數據流ID,用來區分它屬於哪一個數據流。另外還規定,客戶端發出的數據流,ID一概爲奇數,服務器發出的,ID爲偶數。
數據流發送到一半的時候,客戶端和服務器均可以發送信號(RST_STREAM
幀),取消這個數據流。1.1版取消數據流的惟一方法,就是關閉TCP鏈接。這就是說,HTTP/2 能夠取消某一次請求,同時保證TCP鏈接還打開着,能夠被其餘請求使用。
客戶端還能夠指定數據流的優先級。優先級越高,服務器就會越早迴應。
HTTP 協議不帶有狀態,每次請求都必須附上全部信息。因此,請求的不少字段都是重複的,好比Cookie
和User Agent
,如出一轍的內容,每次請求都必須附帶,這會浪費不少帶寬,也影響速度。
HTTP/2 對這一點作了優化,引入了頭信息壓縮機制(header compression
)。一方面,頭信息使用gzip
或compress
壓縮後再發送;另外一方面,客戶端和服務器同時維護一張頭信息表,全部字段都會存入這個表,生成一個索引號,之後就不發送一樣字段了,只發送索引號,這樣就提升速度了。
HTTP/2 容許服務器未經請求,主動向客戶端發送資源,這叫作服務器推送(server push
)。
常見場景是客戶端請求一個網頁,這個網頁裏面包含不少靜態資源。正常狀況下,客戶端必須收到網頁後,解析HTML源碼,發現有靜態資源,再發出靜態資源請求。其實,服務器能夠預期到客戶端請求網頁後,極可能會再請求靜態資源,因此就主動把這些靜態資源隨着網頁一塊兒發給客戶端了。
HTTP協議定義Web客戶端如何從Web服務器請求Web頁面,以及服務器如何把Web頁面傳送給客戶端。HTTP協議採用了請求/響應模型。客戶端向服務器發送一個請求報文,請求報文包含請求的方法、URL、協議版本、請求頭部和請求數據。服務器以一個狀態行做爲響應,響應的內容包括協議的版本、成功或者錯誤代碼、服務器信息、響應頭部和響應數據。
如下是 HTTP 請求/響應的步驟:
一、客戶端鏈接到Web服務器
一個HTTP客戶端,一般是瀏覽器,與Web服務器的HTTP端口(默認爲80)創建一個TCP套接字鏈接。例如,www.oakcms.cn。
二、發送HTTP請求
經過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成。
三、服務器接受請求並返回HTTP響應
Web服務器解析請求,定位請求資源。服務器將資源複本寫到TCP套接字,由客戶端讀取。一個響應由狀態行、響應頭部、空行和響應數據4部分組成。
四、釋放鏈接TCP鏈接
若connection
模式爲close
,則服務器主動關閉TCP鏈接,客戶端被動關閉鏈接,釋放TCP鏈接;若connection
模式爲keepalive
,則該鏈接會保持一段時間,在該時間內能夠繼續接收請求;
五、客戶端瀏覽器解析HTML內容
客戶端瀏覽器首先解析狀態行,查看代表請求是否成功的狀態代碼。而後解析每個響應頭,響應頭告知如下爲若干字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,並在瀏覽器窗口中顯示。
通訊使用明文(不加密),內容可能會被竊聽。
不驗證通訊方的身份,所以可能遭遇假裝
沒法證實報文的完整性,因此有可能已遭篡改。
HTTPS並不是是應用層的一種新協議,只是 HTTP 通訊接口部分用SSL(Secure Socket Layer
)和 TLS (Transport Layer Security
)協議代替而已。 一般,HTTP直接和 TCP 通訊。當使用 SSL 時,則演變成先和 SSL 通訊,再有SSL 和 TCP 通訊了。簡言之,所謂的HTTPS,其實就是身披 SSL 協議這層外殼的 HTTP。 在採用SSL後,HTTP就擁有了 HTTPS 的加密、證書和完整性保護這些功能。
SSL 是獨立於HTTP的協議,因此不光是HTTP協議,其餘運行在應用層的 SMTP
和 Telnet
等協議都可配合 SSL 協議使用。能夠說 SSL 是當今世界應用最爲普遍的網絡安全技術。
HTTPS採用共享密鑰加密和公開密鑰加密的混合加密機制。
共享密鑰加密
加密和解密同用一個密鑰的方式稱爲共享密鑰加密,也被稱爲 對稱密鑰加密。 以共享密鑰方式加密時必須將密鑰也發給對方。可究竟怎樣才能安全地轉交?在互聯網上轉發密鑰時,若是通訊被監聽那麼密鑰就可會落入攻擊者以後,同時也就失去了加密的意義,另外還得設法安全地保管接收到的密鑰。
使用兩把密鑰的公開密鑰加密
公開密鑰加密的方式很好的解決了共享密鑰加密的問題。 公開密鑰加密使用一對非對稱的密鑰。一把爲私鑰(私有密鑰),一把爲公鑰(公開密鑰),其中私有密鑰不能讓任何人得知,而公開密鑰則能夠隨意公佈。 發送密文的那一端,使用對方的公開密鑰進行加密處理,對方接收到被加密的信息後,使用私鑰對此密文進行解密。 利用這種方式,不須要發送用來解密的私鑰。從而解決了共享密鑰加密存在的問題。
使用混合加密機制的HTTPS
HTTPS採用共享密鑰加密和公開密鑰加密的混合加密機制。若是爲了實現密鑰的安全,那麼能夠考慮僅使用公開密鑰加密技術。(公開密鑰加密比共享密鑰加密處理速度要慢) 因此,應當充分利用二者的優點,將多種方法組合起來進行通訊: 在交換密鑰環節,使用公開密鑰加密技術(好比說,從客戶端到服務器,那麼在這樣一個安全的通訊中,客戶端能夠將共享密鑰加密中的密鑰用公開密鑰加密中的公鑰進行加密,發送給服務器,而後服務器使用公開密鑰加密技術的私鑰進行解密,就拿到了共享密鑰加密技術中的私鑰),以後創建通訊報文交換的階段則可以使用共享密鑰加密技術。
1.客戶端首先會將本身支持的加密算法,打個包告訴服務器端。
2.服務器端從客戶端發來的加密算法中,選出一組加密算法和HASH算法(注,HASH也屬於加密),並將本身的身份信息以證書的形式發回給客戶端。而證書中包含了網站的地址,加密用的公鑰,以及證書的頒發機構等;
3.客戶端收到了服務器發來的數據包後,驗證一下證書是否合法,若是證書合法,或者客戶端接受和信任了不合法的證書,則客戶端就會隨機產生一串序列號,使用服務器發來的公鑰進行加密。這時候,一條返回的消息就基本就緒。最後使用服務器挑選的HASH算法,將剛纔的消息使用剛纔的隨機數進行加密,生成相應的消息校驗值,與剛纔的消息一同發還給服務器。
4.服務器接受到客戶端發來的消息後,使用私鑰解密上面公鑰加密的消息,獲得客戶端產生的隨機序列號。使用該隨機序列號,對該消息進行加密,驗證獲得的校驗值是否與客戶端發來的一致。若是一致則說明消息未被篡改,能夠信任。最後,使用該隨機序列號,加上以前選擇的加密算法,加密一段握手消息,發還給客戶端。同時HASH值也帶上。
5.客戶端收到服務器端的消息後,計算HASH值是否與發回的消息一致,檢查消息是否爲握手消息。
6.握手結束後,客戶端和服務器端使用握手階段產生的隨機數以及挑選出來的算法進行對稱加解密的傳輸。
參考文獻:圖解HTTP