http協議各個版本

1、HTTP協議版本更替

HTTP/0.9

        HTTP協議的最第一版本,功能簡陋,僅支持請求方式GET,而且僅能請求訪問HTML格式的資源。javascript

HTTP/1.0    

請求行必須在尾部添加協議版本字段(http/1.0);必須包含頭消息        css

在0.9版本上作了進步,增長了請求方式POST和HEAD;再也不侷限於0.9版本的HTML格式,根據Content-Type能夠支持多種數據格式,即MIME多用途互聯網郵件擴展,例如text/html、image/jpeg等;同時也開始支持cache,就是當客戶端在規定時間內訪問統一網站,直接訪問cache便可。html

再次,HTTP請求和迴應的格式也變了。除了數據部分,每次通訊都必須包括頭信息(HTTP header),用來描述一些元數據。java

其餘的新增功能還包括狀態碼(status code)、多字符集支持、多部分發送(multi-part type)、權限(authorization)、緩存(cache)、內容編碼(content encoding)等。web

        可是1.0版本的工做方式是每次TCP鏈接只能發送一個請求,當服務器響應後就會關閉此次鏈接,下一個請求須要再次創建TCP鏈接,就是不支持keepalive。瀏覽器

        TCP鏈接的新建成本很高,由於須要客戶端和服務器三次握手,而且開始時發送速率較慢(slow start)。因此,HTTP 1.0版本的性能比較差。隨着網頁加載的外部資源愈來愈多,這個問題就愈發突出了。緩存

爲了解決這個問題,有些瀏覽器在請求時,用了一個非標準的Connection字段。性能優化

 
  1.  
  2. Connection: keep-alive服務器

這個字段要求服務器不要關閉TCP鏈接,以便其餘請求複用。服務器一樣迴應這個字段。網絡

 
  1.  
  2. Connection: keep-alive

一個能夠複用的TCP鏈接就創建了,直到客戶端或服務器主動關閉鏈接。可是,這不是標準字段,不一樣實現的行爲可能不一致,所以不是根本的解決辦法。

Content-Type 字段

關於字符的編碼,1.0版規定,頭信息必須是 ASCII 碼,後面的數據能夠是任何格式。所以,服務器迴應的時候,必須告訴客戶端,數據是什麼格式,這就是Content-Type字段的做用。

下面是一些常見的Content-Type字段的值。

  • text/plain
  • text/html
  • text/css
  • image/jpeg
  • image/png
  • image/svg+xml
  • audio/mp4
  • video/mp4
  • application/javascript
  • application/pdf
  • application/zip
  • application/atom+xml

這些數據類型總稱爲MIME type,每一個值包括一級類型和二級類型,之間用斜槓分隔。

除了預約義的類型,廠商也能夠自定義類型。

 
  1.  
  2. application/vnd.debian.binary-package

上面的類型代表,發送的是Debian系統的二進制數據包。

MIME type還能夠在尾部使用分號,添加參數。

 
  1.  
  2. Content-Type: text/html; charset=utf-8

上面的類型代表,發送的是網頁,並且編碼是UTF-8。

客戶端請求的時候,可使用Accept字段聲明本身能夠接受哪些數據格式。

 
  1.  
  2. Accept: */*

上面代碼中,客戶端聲明本身能夠接受任何格式的數據。

MIME type不只用在HTTP協議,還能夠用在其餘地方,好比HTML網頁。

 
  1.  
  2. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

  3. <!-- 等同於 -->

  4. <meta charset="utf-8" />

Content-Encoding 字段

因爲發送的數據能夠是任何格式,所以能夠把數據壓縮後再發送。Content-Encoding字段說明數據的壓縮方法。

 
  1.  
  2. Content-Encoding: gzip

  3. Content-Encoding: compress

  4. Content-Encoding: deflate

客戶端在請求時,用Accept-Encoding字段說明本身能夠接受哪些壓縮方法。

 
  1.  
  2. Accept-Encoding: gzip, deflate

HTTP/1.1    

1.1 版的最大變化,就是引入了持久鏈接(persistent connection),即TCP鏈接默認不關閉,能夠被多個請求複用,不用聲明Connection: keep-alive。解決了1.0版本的keepalive問題,1.1版本加入了持久鏈接,一個TCP鏈接能夠容許多個HTTP請求;

客戶端和服務器發現對方一段時間沒有活動,就能夠主動關閉鏈接。不過,規範的作法是,客戶端在最後一個請求時,發送Connection: close,明確要求服務器關閉TCP鏈接。

 
  1.  
  2. Connection: close

目前,對於同一個域名,大多數瀏覽器容許同時創建6個持久鏈接。下降了延遲同時提升了帶寬的利用率。

    

加入了管道機制,在同一個TCP鏈接裏,容許多個請求同時發送,增長了併發性,進一步改善了HTTP協議的效率;舉例來講,客戶端須要請求兩個資源。之前的作法是,在同一個TCP鏈接裏面,先發送A請求,而後等待服務器作出迴應,收到後再發出B請求。管道機制則是容許瀏覽器同時發出A請求和B請求,可是服務器仍是按照順序,先回應A請求,完成後再回應B請求。

Content-Length 字段

一個TCP鏈接如今能夠傳送多個迴應,勢必就要有一種機制,區分數據包是屬於哪個迴應的。這就是Content-length字段的做用,聲明本次迴應的數據長度。

 
  1.  
  2. Content-Length: 3495

上面代碼告訴瀏覽器,本次迴應的長度是3495個字節,後面的字節就屬於下一個迴應了。

在1.0版中,Content-Length字段不是必需的,由於瀏覽器發現服務器關閉了TCP鏈接,就代表收到的數據包已經全了。

分塊傳輸編碼

使用Content-Length字段的前提條件是,服務器發送迴應以前,必須知道迴應的數據長度。

對於一些很耗時的動態操做來講,這意味着,服務器要等到全部操做完成,才能發送數據,顯然這樣的效率不高。更好的處理方法是,產生一塊數據,就發送一塊,採用"流模式"(stream)取代"緩存模式"(buffer)。

所以,1.1版規定能夠不使用Content-Length字段,而使用"分塊傳輸編碼"(chunked transfer encoding)。只要請求或迴應的頭信息有Transfer-Encoding字段,就代表迴應將由數量未定的數據塊組成。

 
  1.  
  2. Transfer-Encoding: chunked

每一個非空的數據塊以前,會有一個16進制的數值,表示這個塊的長度。最後是一個大小爲0的塊,就表示本次迴應的數據發送完了。下面是一個例子。

 
  1.  
  2. HTTP/1.1 200 OK

  3. Content-Type: text/plain

  4. Transfer-Encoding: chunked

  5.  
  6. 25

  7. This is the data in the first chunk

  8.  
  9. 1C

  10. and this is the second one

  11.  
  12. 3

  13. con

  14.  
  15. 8

  16. sequence

  17.  
  18. 0

新增了請求方式PUT、PATCH、OPTIONS、DELETE等。

另外,客戶端請求的頭信息新增了Host字段,用來指定服務器的域名。在HTTP1.0中認爲每臺服務器都綁定一個惟一的IP地址,所以,請求消息中的URL並無傳遞主機名(hostname)。但隨着虛擬主機技術的發展,在一臺物理服務器上能夠存在多個虛擬主機(Multi-homed Web Servers),而且它們共享一個IP地址。

 
  1.  
  2. Host: www.example.com

有了Host字段,就能夠將請求發往同一臺服務器上的不一樣網站,爲虛擬主機的興起打下了基礎。(實現了在一臺WEB服務器上能夠在同一個IP地址和端口號上使用不一樣的主機名來建立多個虛擬WEB站點。也便是說,web server上的多個虛擬站點能夠共享同一個ip和端口。)且請求消息中若是沒有Host頭域會報告一個錯誤(400 Bad Request)。

        雖然1.1版容許複用TCP鏈接,可是同一個TCP鏈接裏面,全部的數據通訊是按次序進行的。服務端是按隊列順序處理請求的,服務器只有處理完一個迴應,纔會進行下一個迴應。假如前面的請求處理時間很長,後面就會有許多請求排隊等着,這樣就形成了「隊頭阻塞」的問題;同時HTTP是無狀態的鏈接,所以每次請求都須要添加劇復的字段,下降了帶寬的利用率。

多路複用帶來一個新的問題是,在鏈接共享的基礎之上有可能會致使關鍵請求被阻塞。SPDY容許給每一個request設置優先級,這樣重要的請求就會優先獲得響應。好比瀏覽器加載首頁,首頁的html內容應該優先展現,以後纔是各類靜態資源文件,腳本文件等加載,這樣能夠保證用戶能第一時間看到網頁內容。

爲了不這個問題,只有兩種方法:一是減小請求數,二是同時多開持久鏈接。這致使了不少的網頁優化技巧,好比合並腳本和樣式表、將圖片嵌入CSS代碼、域名分片(domain sharding)等等。若是HTTP協議設計得更好一些,這些額外的工做是能夠避免的。

100(Continue) Status(節約帶寬)

HTTP/1.1加入了一個新的狀態碼100(Continue)。客戶端事先發送一個只帶頭域的請求,若是服務器由於權限拒絕了請求,就回送響應碼401(Unauthorized);若是服務器接收此請求就回送響應碼100,客戶端就能夠繼續發送帶實體的完整請求了。100 (Continue) 狀態代碼的使用,容許客戶端在發request消息body以前先用request header試探一下server,看server要不要接收request body,再決定要不要發request body。

HTTP/1.1在1.0的基礎上加入了一些cache的新特性,當緩存對象的Age超過Expire時變爲stale對象,cache不須要直接拋棄stale對象,而是與源服務器進行從新激活(revalidation)。

HTTP 1.1支持只發送header信息(不帶任何body信息),若是服務器認爲客戶端有權限請求服務器,則返回100,不然返回401。客戶端若是接受到100,纔開始把請求body發送到服務器。這樣當服務器返回401的時候,客戶端就能夠不用發送請求body了,節約了帶寬。

HTTP1.1還有身份認證機制,許多web站點要求用戶提供一個用戶名—口令對才能訪問存放在其服務器中的文檔,這種要求稱爲身份認證(authentication)。HTTP提供特殊的狀態碼和頭部來幫助Web站點執行身份認證。

HTTP支持傳送內容的一部分。這樣當客戶端已經有一部分的資源後,只須要跟服務器請求另外的部分資源便可。這是支持文件斷點續傳的基礎。

HTTP/1.1支持文件斷點續傳,RANGE:bytes,HTTP/1.0每次傳送文件都是從文件頭開始,即0字節處開始。RANGE:bytes=XXXX表示要求服務器從文件XXXX字節處開始傳送,斷點續傳。即返回碼是206(Partial Content)

在HTTP1.1中新增了24個錯誤狀態響應碼,如409(Conflict)表示請求的資源與資源的當前狀態發生衝突;410(Gone)表示服務器上的某個資源被永久性的刪除。

HTTP/2.0

        爲了解決1.1版本利用率不高的問題,提出了HTTP/2.0版本。增長雙工模式,即不只客戶端可以同時發送多個請求,服務端也能同時處理多個請求,解決了隊頭堵塞的問題(HTTP2.0使用了多路複用的技術,作到同一個鏈接併發處理多個請求,並且併發請求的數量比HTTP1.1大了好幾個數量級);HTTP請求和響應中,狀態行和請求/響應頭都是些信息字段,並無真正的數據,所以在2.0版本中將全部的信息字段創建一張表,爲表中的每一個字段創建索引,客戶端和服務端共同使用這個表,他們之間就以索引號來表示信息字段,這樣就避免了1.0舊版本的重複繁瑣的字段,並以壓縮的方式傳輸,提升利用率。

        另外也增長服務器推送的功能,即不經請求服務端主動向客戶端發送數據。

當前主流的協議版本仍是HTTP/1.1版本。

二進制協議

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 協議不帶有狀態,每次請求都必須附上全部信息。因此,請求的不少字段都是重複的,好比CookieUser Agent,如出一轍的內容,每次請求都必須附帶,這會浪費不少帶寬,也影響速度。

HTTP/2 對這一點作了優化,引入了頭信息壓縮機制(header compression)。一方面,頭信息使用gzipcompress壓縮後再發送;另外一方面,客戶端和服務器同時維護一張頭信息表,全部字段都會存入這個表,生成一個索引號,之後就不發送一樣字段了,只發送索引號,這樣就提升速度了。

服務器推送

HTTP/2 容許服務器未經請求,主動向客戶端發送資源,這叫作服務器推送(server push)。

意思是說,當咱們對支持HTTP2.0的web server請求數據的時候,服務器會順便把一些客戶端須要的資源一塊兒推送到客戶端,省得客戶端再次建立鏈接發送請求到服務器端獲取。這種方式很是合適加載靜態資源。

服務器端推送的這些資源其實存在客戶端的某處地方,客戶端直接從本地加載這些資源就能夠了,不用走網絡,速度天然是快不少的。

常見場景是客戶端請求一個網頁,這個網頁裏面包含不少靜態資源。正常狀況下,客戶端必須收到網頁後,解析HTML源碼,發現有靜態資源,再發出靜態資源請求。其實,服務器能夠預期到客戶端請求網頁後,極可能會再請求靜態資源,因此就主動把這些靜態資源隨着網頁一塊兒發給客戶端了。

服務端推送能把客戶端所須要的資源伴隨着index.html一塊兒發送到客戶端,省去了客戶端重複請求的步驟。正由於沒有發起請求,創建鏈接等操做,因此靜態資源經過服務端推送的方式能夠極大地提高速度。

普通的客戶端請求過程:

服務端推送的過程:

HTTP 性能優化的關鍵並不在於高帶寬,而是低延遲。TCP 鏈接會隨着時間進行自我「調諧」,起初會限制鏈接的最大速度,若是數據成功傳輸,會隨着時間的推移提升傳輸的速度。這種調諧則被稱爲 TCP 慢啓動(擁塞控制)。因爲這種緣由,讓本來就具備突發性和短時性的 HTTP 鏈接變的十分低效。
HTTP/2 經過讓全部數據流共用同一個鏈接,能夠更有效地使用 TCP 鏈接,讓高帶寬也能真正的服務於 HTTP 的性能提高。

2、HTTP響應模型

        服務器收到HTTP請求以後,會有多種方法響應這個請求,下面是HTTP響應的四種模型:

        單進程I/O模型

服務端開啓一個進程,一個進程僅能處理一個請求,而且對請求順序處理;

        多進程I/O模型

服務端並行開啓多個進程,一樣的一個進程只能處理一個請求,這樣服務端就能夠同時處理多個請求;

        複用I/O模型

服務端開啓一個進程,可是呢,同時開啓多個線程,一個線程響應一個請求,一樣能夠達到同時處理多個請求,線程間併發執行;

        複用多線程I/O模型

服務端並行開啓多個進程,同時每一個進程開啓多個線程,這樣服務端能夠同時處理進程數M*每一個進程的線程數N個請求。

相關文章
相關標籤/搜索