【業務學習】2019-05-09 http1.1&2.0的基本原理

Grape
所有視頻:https://segmentfault.com/a/11...算法


http的定義

HTTP是基於客戶端/服務端(C/S)的架構模型,經過一個可靠的連接來交換信息,是一個無狀態的請求/響應協議。

http的結構

clipboard.png

咱們目前用到最多的是http1.x協議,header和body咱們都不陌生,那麼startline是什麼呢?startline是咱們所說的request_line或status_line,也就是
GET /HTTP/1.1或者HTTP/1.1 200 OK這種字段。
在敘述http的各類工做方式以前,咱們先熟悉一下TCP/IP模型:segmentfault

clipboard.png

http的發展:

http1.0

Http1.0:http1.0是默認沒有keep-alive的,在數據請求的時候會先進性應用層如下的處理過程纔會到應用層,在這裏咱們只說傳輸層和應用層,在http1.0中,每一次的請求都會進行創建tcp鏈接(三次握手),而後進行http請求,這樣每次與服務器交互,都須要新開一個鏈接!咱們的每一個連接的請求鏈路都以下圖所示:瀏覽器

clipboard.png

想象一下,每發起一個請求就通過上述如此長的一個流程,這將耗去多少資源。緩存

http1.1

基於這個問題,咱們的http迎來了http1.1版本,1.1版本相對於1.0版本有什麼改動呢?安全

  • http增長了host字段
  • HTTP 1.1中引入了Chunked transfer-coding,範圍請求,實現斷點續傳(實際上就是利用HTTP消息頭使用分塊傳輸編碼,將實體主體分塊傳輸)
  • HTTP 1.1管線化(pipelining)理論,客戶端能夠同時發出多個HTTP請求,而不用一個個等待響應以後再請求服務器

    • 注意:這個pipelining僅僅是限於理論場景下,大部分桌面瀏覽器仍然會選擇默認關閉HTTP pipelining!
    • 因此如今使用HTTP1.1協議的應用,都是有可能會開多個TCP鏈接的!

Http1.1基於上述耗費資源的問題給予了根本的處理,默認長連接,什麼意思呢? 不去在每個http請求的時候都去進行http鏈接,只創建一個tcp連接去處理多個請求,固然,這裏的每一個請求是串行的,即只是不用去進行tcp鏈接,仍是得排隊,而且這樣子可能會引發線頭阻塞(例如發送100個請求,第一個被阻塞致使後邊99個也不能請求)問題。對於http1.1默認的工做模式以下圖所示:網絡

clipboard.png

到這咱們想象一下這種模式好麼,有什麼缺點?能夠優化嗎?
在此之上咱們已經拋出了兩個問題1.須要排隊 2.可能引發線頭阻塞。對於第一個問題,http1.1已經給出瞭解決方案,即pipline,而第二個問題剛開始有一種過渡的方案,即spdy協議(google推出的一項加強http的協議,功能包括數據流的多路複用、請求優先級以及HTTP報頭壓縮,有興趣的能夠研究一下),而後再到如今的http2.0。
首先咱們先說一下什麼是pipline,pipline是一項實現了多個http請求但不須要等待響應就可以寫進同一個socket的技術,僅有http1.1規範支持http管線化,1.0並不支持。什麼意思呢?咱們看上圖是在一個tcp鏈接的串行的去處理,那麼開啓了pipline以後就會變成下邊這個樣子:架構

clipboard.png

咱們能夠看到發送http請求再也不是先發送而後等待response再發送下個請求了,這樣子咱們能夠當作是全部的請求統一開始,可是這有一個問題,HTTP Pipelining實際上是把多個HTTP請求放到一個TCP鏈接中一一發送,而在發送過程當中不須要等待服務器對前一個請求的響應;只不過,客戶端仍是要按照發送請求的順序來接收響應!這就致使了它雖然解決了排隊問題,可是他也僅僅是解決了單方排隊的問題,最後接受數據仍是按照請求的順序來接受相應,爲何呢?由於他們不知道哪一個是第一個哪一個是第二個。這樣一樣會存在線頭阻塞的問題。
總結一下就是在http1.0的時候咱們是流水線,一個接一個的完成任務,http1.1的時候呢咱們工人的能力提高了,能夠一次發出多個工做需求了,可是尚未掌握技巧,仍是得按照條例等待工做所有到來的時候一個一個按順序處理。socket

http2.0

接下來就是咱們的http2.0,看他如何解決了以前的問題。解決線頭阻塞,在http2.0中實際上是用了一個stream的結構,給每個stream分配一個標示即streamId就能夠來解決線頭阻塞的問題。那麼http2到底是何方神聖呢?
首先,提及http2,咱們不得不提一下https,http2是基於https的一個協議,對於https我找了一篇寫的比較好的文章,Wireshark 抓包理解 HTTPS 請求流程
文章開頭咱們對比了http1和http2的結構,看起來好像徹底不同,可是實際上並不是如此,http2以幀做爲最小單位,看了下邊的圖咱們會發現原來http2只是作了層封裝,其實本質仍是headers和body,只不過http2是以更高級功能更多的方式進行了展現。tcp

clipboard.png

http1.x vs http2.0

關於http2好在哪裏,那咱們得從http1壞出發,由於有對比才會有傷害。

  • http1鏈接數限制,對於同一個域名,瀏覽器最多隻能同時建立 6~8 個 TCP 鏈接 (不一樣瀏覽器不同)。爲了解決數量限制,出現了 域名分片 技術,其實就是資源分域,將資源放在不一樣域名下 (好比二級子域名下),這樣就能夠針對不一樣域名建立鏈接並請求,以一種討巧的方式突破限制,可是濫用此技術也會形成不少問題,好比每一個 TCP 鏈接自己須要通過 DNS 查詢、三步握手、慢啓動等,還佔用額外的 CPU 和內存,對於服務器來講過多鏈接也容易形成網絡擁擠、交通阻塞等。那麼,http2是怎麼作的呢?http2採用了多路複用技術,在一個 TCP 鏈接上,咱們能夠向對方不斷髮送幀,每幀的 stream_id標明這一幀屬於哪一個流,而後在對方接收時,根據 stream_id拼接每一個流的全部幀組成一整塊數據。把 HTTP/1.1 每一個請求都看成一個流,那麼多個請求變成多個流,請求響應數據分紅多個幀,不一樣流中的幀交錯地發送給對方,這就是 HTTP/2 中的多路複用。同時呢,咱們知道http1的body長度是在header帶過來的,那麼若是是以http2的形式去傳輸確定會出問題,因此http2將body上架了length字段,每個流都有本身的長度,最後根據流的頭部長度是否等於各個流的長度來肯定是否合包。同時呢,這樣分包合包也解決了線頭阻塞的問題。那麼問題又來了,怎麼肯定沒有丟包?同一個stream秩序有沒有亂?這點tcp會保證包的有序性且保證了包不會丟失。
  • Header 內容多,並且每次請求 Header 不會變化太多,沒有相應的壓縮傳輸優化方案。http2在此用hpack算法來壓縮首部長度,其原理就是維護一個靜態索引表和動態索引表的索引空間,hpack其原理就是匹配當前鏈接存在的索引空間,若某個鍵值已存在,則用相應的索引代替首部條目,好比 「:method: GET」 能夠匹配到靜態索引中的 index 2,傳輸時只須要傳輸一個包含 2 的字節便可;若索引空間中不存在,則用字符編碼傳輸,字符編碼能夠選擇哈夫曼編碼,而後分狀況判斷是否須要存入動態索引表中,以這種形式節省了不少的空間。
  • 明文傳輸不安全。http1使用明文傳輸,不安全。那麼http2就用二進制分幀層來解決這個問題,幀是數據傳輸的最小單位,以二進制傳輸代替本來的明文傳輸,本來的報文消息被劃分爲更小的數據幀。
  • 爲了儘量減小請求數,須要作合併文件、雪碧圖、資源內聯等優化工做,可是這無疑形成了單個請求內容變大延遲變高的問題,且內嵌的資源不能有效地使用緩存機制。對於這種狀況,http2推出了服務端推送,瀏覽器發送一個請求,服務器主動向瀏覽器推送與這個請求相關的資源,這樣瀏覽器就不用發起後續請求,其主要是針對資源內聯作出的優化。
  • 應用層的重置鏈接,對於 HTTP/1 來講,是經過設置 tcp segment 裏的 reset flag 來通知對端關閉鏈接的。這種方式會直接斷開鏈接,下次再發請求就必須從新創建鏈接。HTTP/2 引入 RST_STREAM 類型的 frame,能夠在不斷開鏈接的前提下取消某個 request 的 stream,表現更好。

擴展

關於http咱們就說這麼多,若是想了解的更多讀者能夠自行用wireshark抓包看一下。推薦兩個比較好的抓包工具:wireshark和charles。

參考文章:

相關文章
相關標籤/搜索