本篇是對
HTTP
不一樣版本主要特性的一個概述和總結。
早先1.0
的HTTP
版本,是一種無狀態、無鏈接的應用層協議。css
HTTP1.0
規定瀏覽器和服務器保持短暫的鏈接,瀏覽器的每次請求都須要與服務器創建一個TCP
鏈接,服務器處理完成後當即斷開TCP
鏈接(無鏈接),服務器不跟蹤每一個客戶端也不記錄過去的請求(無狀態)。html
這種無狀態性能夠藉助cookie/session
機制來作身份認證和狀態記錄。而下面兩個問題就比較麻煩了。web
首先,無鏈接的特性致使最大的性能缺陷就是沒法複用鏈接。每次發送請求的時候,都須要進行一次TCP
的鏈接,而TCP
的鏈接釋放過程又是比較費事的。這種無鏈接的特性會使得網絡的利用率很是低。算法
其次就是隊頭阻塞(head of line blocking
)。因爲HTTP1.0
規定下一個請求必須在前一個請求響應到達以前才能發送。假設前一個請求響應一直不到達,那麼下一個請求就不發送,一樣的後面的請求也給阻塞了。segmentfault
爲了解決這些問題,HTTP1.1
出現了。瀏覽器
對於HTTP1.1
,不只繼承了HTTP1.0
簡單的特色,還克服了諸多HTTP1.0
性能上的問題。緩存
首先是長鏈接,HTTP1.1
增長了一個Connection
字段,經過設置Keep-Alive
能夠保持HTTP
鏈接不斷開,避免了每次客戶端與服務器請求都要重複創建釋放創建TCP
鏈接,提升了網絡的利用率。若是客戶端想關閉HTTP
鏈接,能夠在請求頭中攜帶Connection: false
來告知服務器關閉請求。服務器
其次,是HTTP1.1
支持請求管道化(pipelining
)。基於HTTP1.1
的長鏈接,使得請求管線化成爲可能。管線化使得請求可以「並行」傳輸。舉個例子來講,假如響應的主體是一個html
頁面,頁面中包含了不少img
,這個時候keep-alive
就起了很大的做用,可以進行「並行」發送多個請求。(注意這裏的「並行」並非真正意義上的並行傳輸,具體解釋以下。)cookie
須要注意的是,服務器必須按照客戶端請求的前後順序依次回送相應的結果,以保證客戶端可以區分出每次請求的響應內容。網絡
也就是說,HTTP
管道化可讓咱們把先進先出隊列從客戶端(請求隊列)遷移到服務端(響應隊列)。
如圖所示,客戶端同時發了兩個請求分別來獲取html
和css
,假如說服務器的css
資源先準備就緒,服務器也會先發送html
再發送css
。
換句話來講,只有等到html
響應的資源徹底傳輸完畢後,css
響應的資源才能開始傳輸。也就是說,不容許同時存在兩個並行的響應。
可見,HTTP1.1
仍是沒法解決隊頭阻塞(head of line blocking
)的問題。同時「管道化」技術存在各類各樣的問題,因此不少瀏覽器要麼根本不支持它,要麼就直接默認關閉,而且開啓的條件很苛刻...並且實際上好像並無什麼用處。
那咱們在谷歌控制檯看到的並行請求又是怎麼一回事呢?
如圖所示,綠色部分表明請求發起到服務器響應的一個等待時間,而藍色部分表示資源的下載時間。按照理論來講,HTTP響應理應當是前一個響應的資源下載完了,下一個響應的資源才能開始下載。而這裏卻出現了響應資源下載並行的狀況。這又是爲何呢?
其實,雖然HTTP1.1
支持管道化,可是服務器也必須進行逐個響應的送回,這個是很大的一個缺陷。實際上,現階段的瀏覽器廠商採起了另一種作法,它容許咱們打開多個TCP的會話。也就是說,上圖咱們看到的並行,實際上是不一樣的TCP鏈接上的HTTP
請求和響應。這也就是咱們所熟悉的瀏覽器對同域下並行加載6~8個資源的限制。而這,纔是真正的並行!
此外,HTTP1.1
還加入了緩存處理(強緩存和協商緩存[傳送門])新的字段如cache-control
,支持斷點傳輸,以及增長了Host字段(使得一個服務器可以用來建立多個Web站點)。
HTTP2.0
的新特性大體以下:
二進制分幀
HTTP2.0
經過在應用層和傳輸層之間增長一個二進制分幀層,突破了HTTP1.1
的性能限制、改進傳輸性能。
可見,雖然HTTP2.0
的協議和HTTP1.x
協議之間的規範徹底不一樣了,可是實際上HTTP2.0
並無改變HTTP1.x
的語義。
簡單來講,HTTP2.0
只是把原來HTTP1.x
的header
和body
部分用frame
從新封裝了一層而已。
多路複用(鏈接共享)
下面是幾個概念:
stream
):已創建鏈接上的雙向字節流。frame
):HTTP2.0
通訊的最小單位,每一個幀包含幀頭部,至少也會標識出當前幀所屬的流(stream id
)。從圖中可見,全部的HTTP2.0
通訊都在一個TCP
鏈接上完成,這個鏈接能夠承載任意數量的雙向數據流。
每一個數據流以消息的形式發送,而消息由一或多個幀組成。這些幀能夠亂序發送,而後再根據每一個幀頭部的流標識符(stream id
)從新組裝。
舉個例子,每一個請求是一個數據流,數據流以消息的方式發送,而消息又分爲多個幀,幀頭部記錄着stream id
用來標識所屬的數據流,不一樣屬的幀能夠在鏈接中隨機混雜在一塊兒。接收方能夠根據stream id
將幀再歸屬到各自不一樣的請求當中去。
另外,多路複用(鏈接共享)可能會致使關鍵請求被阻塞。HTTP2.0
裏每一個數據流均可以設置優先級和依賴,優先級高的數據流會被服務器優先處理和返回給客戶端,數據流還能夠依賴其餘的子數據流。
可見,HTTP2.0
實現了真正的並行傳輸,它可以在一個TCP
上進行任意數量HTTP
請求。而這個強大的功能則是基於「二進制分幀」的特性。
頭部壓縮
在HTTP1.x
中,頭部元數據都是以純文本的形式發送的,一般會給每一個請求增長500~800字節的負荷。
好比說cookie
,默認狀況下,瀏覽器會在每次請求的時候,把cookie
附在header
上面發送給服務器。(因爲cookie
比較大且每次都重複發送,通常不存儲信息,只是用來作狀態記錄和身份認證)
HTTP2.0
使用encoder
來減小須要傳輸的header
大小,通信雙方各自cache
一份header fields
表,既避免了重複header
的傳輸,又減少了須要傳輸的大小。高效的壓縮算法能夠很大的壓縮header
,減小發送包的數量從而下降延遲。
服務器推送
服務器除了對最初請求的響應外,服務器還能夠額外的向客戶端推送資源,而無需客戶端明確的請求。
首先,答案是「沒有必要」。之因此沒有必要,是由於這跟HTTP2.0
的頭部壓縮有很大的關係。
在頭部壓縮技術中,客戶端和服務器均會維護兩份相同的靜態字典和動態字典。
在靜態字典中,包含了常見的頭部名稱以及頭部名稱與值的組合。靜態字典在首次請求時就可使用。那麼如今頭部的字段就能夠被簡寫成靜態字典中相應字段對應的index
。
而動態字典跟鏈接的上下文相關,每一個HTTP/2
鏈接維護的動態字典是不盡相同的。動態字典能夠在鏈接中不聽的進行更新。
也就是說,本來完整的HTTP報文頭部的鍵值對或字段,因爲字典的存在,如今能夠轉換成索引index
,在相應的端再進行查找還原,也就起到了壓縮的做用。
因此,同一個鏈接上產生的請求和響應越多,動態字典累積得越全,頭部壓縮的效果也就越好,因此針對HTTP/2
網站,最佳實踐是不要合併資源。
另外,HTTP2.0
多路複用使得請求能夠並行傳輸,而HTTP1.1
合併請求的一個緣由也是爲了防止過多的HTTP
請求帶來的阻塞問題。而如今HTTP2.0
已經可以並行傳輸了,因此合併請求也就沒有必要了。
HTTP1.0
HTTP1.1
cache-control
)Host
字段、支持斷點傳輸等HTTP2.0
參考:
https://www.zhihu.com/questio...
https://segmentfault.com/q/10...
http://imweb.io/topic/554c587...
http://web.jobbole.com/85635/