轉載出處:HTTP 協議漫談css
網絡上已經有很多介紹 HTTP 的好文章,對HTTP的一些細節介紹的比較好,因此本篇文章不會對 HTTP 的細節進行深究,而是從夠高和更結構化的角度將 HTTP 協議的元素進行分類講解。html
在一個網絡中。傳輸數據須要面臨三個問題:瀏覽器
1.客戶端如何知道所求內容的位置?緩存
2.當客戶端知道所求內容的位置後,如何獲取所求內容?服務器
3.所求內容以何種形式組織以便被客戶端所識別?網絡
對於WEB來講,回答上面三種問題分別採用三種不一樣的技術,分別爲:統一資源定位符(URIs),超文本傳輸協議(HTTP)和超文本標記語言(HTML)。對於大多數WEB開發人員來講URI和HTML都是很是的熟悉。而HTTP協議在不少WEB技術中都被封裝的過多使得HTTP反而最不被熟悉。多線程
HTTP做爲一種傳輸協議,也是像HTML同樣隨着時間不斷演進的,目前流行的HTTP1.1是HTTP協議的第三個版本。app
HTTP 0.9框架
HTTP 0.9做爲HTTP協議的第一個版本。是很是弱的。請求(Request)只有一行,好比:ide
1
|
GET www.cnblogs.com
|
從如此簡單的請求體,沒有POST方法,沒有HTTP 頭能夠看出,那個時代的HTTP客戶端只能接收一種類型:純文本。而且,若是得不到所求的信息,也沒有404 500等錯誤出現。
雖然HTTP 0.9看起來如此弱,但已經能知足那個時代的需求了。
HTTP 1.0
隨着1996年後,WEB程序的需求,HTTP 0.9已經不能知足需求。HTTP1.0最大的改變是引入了POST方法,使得客戶端經過HTML表單向服務器發送數據成爲可能,這也是WEB應用程序的一個基礎。另外一個巨大的改變是引入了HTTP頭,使得HTTP不只能返回錯誤代碼,而且HTTP協議所傳輸的內容不只限於純文本,還能夠是圖片,動畫等一系列格式。
除此以外,還容許保持鏈接,既一次TCP鏈接後,能夠屢次通訊,雖然HTTP1.0 默認是傳輸一次數據後就關閉。
HTTP 1.1
2000年5月,HTTP1.1確立。HTTP1.1並不像HTTP1.0對於HTTP0.9那樣的革命性。可是也有不少加強。
首先,增長了Host頭,好比訪問個人博客:
1
2
|
GET /Careyson HTTP/
1.1
Host: www.cnblogs.com
|
Get後面僅僅須要相對路徑便可。這看起來雖然僅僅相似語法糖的感受,但實際上,這個提高使得在Web上的一臺主機能夠存在多個域。不然多個域名指向同一個IP會產生混淆。
此外,還引入了Range頭,使得客戶端經過HTTP下載時只下載內容的一部分,這使得多線程下載也成爲可能。
還有值得一提的是HTTP1.1 默認鏈接是一直保持的,這個概念我會在下文中具體闡述。
在Internet中全部的傳輸都是經過TCP/IP進行的。HTTP協議做爲TCP/IP模型中應用層的協議也不例外。HTTP在網絡中的層次如圖1所示。
能夠看出,HTTP是基於傳輸層的TCP協議,而TCP是一個端到端的面向鏈接的協議。所謂的端到端能夠理解爲進程到進程之間的通訊。因此HTTP在開始傳輸以前,首先須要創建TCP鏈接,而TCP鏈接的過程須要所謂的「三次握手」。概念如圖2所示。
在TCP三次握手以後,創建了TCP鏈接,此時HTTP就能夠進行傳輸了。一個重要的概念是面向鏈接,既HTTP在傳輸完成之間並不斷開TCP鏈接。在HTTP1.1中(經過Connection頭設置)這是默認行爲。所謂的HTTP傳輸完成咱們經過一個具體的例子來看。
好比訪問個人博客,使用Fiddler來截取對應的請求和響應。如圖3所示。
能夠看出,雖然僅僅訪問了個人博客,但鎖獲取的不只僅是一個HTML而已,而是瀏覽器對HTML解析的過程當中,若是發現須要獲取的內容,會再次發起HTTP請求去服務器獲取,好比圖2中的那個common2.css。這上面19個HTTP請求,只依靠一個TCP鏈接就夠了,這就是所謂的持久鏈接。也是所謂的一次HTTP請求完成。
所謂的HTTP請求,也就是Web客戶端向Web服務器發送信息,這個信息由以下三部分組成:
1.請求行
2.HTTP頭
3.內容
一個典型的請求行好比:
1
|
GET www.cnblogs.com HTTP/
1.1
|
請求行寫法是固定的,由三部分組成,第一部分是請求方法,第二部分是請求網址,第三部分是HTTP版本。
第二部分HTTP頭在HTTP請求能夠是3種HTTP頭:1.請求頭(request header) 2.普通頭(general header) 3.實體頭(entity header)
一般來講,因爲Get請求每每不包含內容實體,所以也不會有實體頭。
第三部份內容只在POST請求中存在,由於GET請求並不包含任何實體。
咱們截取一個具體的Post請求來看這三部分,我在一個普通的aspx頁面放一個BUTTON,當提交後會產生一個Post請求,如圖4所示。
HTTP請求方法
雖然咱們所常見的只有Get和Post方法,但實際上HTTP請求方法還有不少,好比: PUT方法,DELETE方法,HEAD方法,CONNECT方法,TRACE方法。這裏我就不細說了,自行Bing。
這裏重點說一下Get和Post方法,網上關於Get和Post的區別滿天飛。但不少沒有說到點子上。Get和Post最大的區別就是Post有上面所說的第三部分:內容。而Get不存在這個內容。所以就像Get和Post其名稱所示那樣,Get用於從服務器上取內容,雖然能夠經過QueryString向服務器發信息,但這違背了Get的本意,QueryString中的信息在HTTP看來僅僅是獲取所取得內容的一個參數而已。而Post是由客戶端向服務器端發送內容的方式。所以具備請求的第三部分:內容。
當Web服務器收到HTTP請求後,會根據請求的信息作某些處理(這些處理可能僅僅是靜態的返回頁,或是包含Asp.net,PHP,Jsp等語言進行處理後返回),相應的返回一個HTTP響應。HTTP響應在結構上很相似於HTTP請求,也是由三部分組成,分別爲:
1.狀態行
2.HTTP頭
3.返回內容
首先來看狀態行,一個典型的HTTP狀態以下:
1
|
HTTP/
1.1
200
OK
|
第一部分是HTTP版本,第二部分是響應狀態碼,第三部分是狀態碼的描述,所以也能夠把第二和第三部分當作一個部分。
對於HTTP版本沒有什麼好說的,而狀態碼值得說一下,網上對於每一個具體的HTTP狀態碼所表明的含義都有解釋,這裏我說一下分類。
HTTP響應中包含的頭包括1.響應頭(response header) 2.普通頭(general header) 3.實體頭(entity header)。
第三部分HTTP響應內容就是HTTP請求所請求的信息。這個信息能夠是一個HTML,也能夠是一個圖片。好比我訪問百度,HTTP Response如圖5所示。
圖5中的響應是一個HTML,固然還能夠是其它類型,好比圖片,如圖6所示。
這裏會有一個疑問,既然HTTP響應的內容不只僅是HTML,還能夠是其它類型,那麼瀏覽器如何正確對接收到的信息進行處理?
這是經過媒體類型肯定的(Media Type),具體來講對應Content-Type這個HTTP頭,好比圖5中是text/html,圖6是image/jpeg。
媒體類型的格式爲:大類/小類 好比圖5中的html是小類,而text是大類。
IANA(The Internet Assigned Numbers Authority,互聯網數字分配機構)定義了8個大類的媒體類型,分別是:
HTTP頭僅僅是一個標籤而已,好比我在Aspx中加入代碼:
Response.AddHeader(「測試頭」,」測試值」);
對應的咱們能夠在fiddler抓到的信息如圖7所示。
不難看出,HTTP頭並非嚴格要求的,僅僅是一個標籤,若是瀏覽器能夠解析就會按照某些標準(好比瀏覽器自身標準,W3C的標準)去解釋這個頭,不然不識別的頭就會被瀏覽器無視。對服務器也是同理。假如你編寫一個瀏覽器,你能夠將上面的頭解釋成任何你想要的效果微笑
下面咱們說的HTTP頭都是W3C標準的頭,我不會對每一個頭的做用進行詳細說明,關於HTTP頭做用的文章在網上已經不少了,請自行Bing。HTTP頭按照其不一樣的做用,能夠分爲四大類。
通用頭(General header)
通用頭便可以包含在HTTP請求中,也能夠包含在HTTP響應中。通用頭的做用是描述HTTP協議自己。好比描述HTTP是否持久鏈接的Connection頭,HTTP發送日期的Date頭,描述HTTP所在TCP鏈接時間的Keep-Alive頭,用於緩存控制的Cache-Control頭等。
實體頭(Entity header)
實體頭是那些描述HTTP信息的頭。既能夠出如今HTTP POST方法的請求中,也能夠出如今HTTP響應中。好比圖5和圖6中的Content-Type和Content-length都是描述實體的類型和大小的頭都屬於實體頭。其它還有用於描述實體的Content-Language,Content-MD5,Content-Encoding以及控制實體緩存的Expires和Last-Modifies頭等。
請求頭(HTTP Request Header)
請求頭是那些由客戶端發往服務端以便幫助服務端更好的知足客戶端請求的頭。請求頭只能出如今HTTP請求中。好比告訴服務器只接收某種響應內容的Accept頭,發送Cookies的Cookie頭,顯示請求主機域的HOST頭,用於緩存的If-Match,If-Match-Since,If-None-Match頭,用於只取HTTP響應信息中部分信息的Range頭,用於附屬HTML相關請求引用的Referer頭等。
響應頭(HTTP Response Header)
HTTP響應頭是那些描述HTTP響應自己的頭,這裏面並不包含描述HTTP響應中第三部分也就是HTTP信息的頭(這部分由實體頭負責)。好比說定時刷新的Refresh頭,當遇到503錯誤時自動重試的Retry-After頭,顯示服務器信息的Server頭,設置COOKIE的Set-Cookie頭,告訴客戶端能夠部分請求的Accept-Ranges頭等。
還有一點值得注意的是,HTTP協議是無狀態的,這意味着對於接收HTTP請求的服務器來講,並不知道每一次請求來自同一個客戶端仍是不一樣客戶端,每一次請求對於服務器來講都是同樣的。所以須要一些額外的手段來使得服務器在接收某個請求時知道這個請求來自於某個客戶端。如圖8所示。
經過Cookies保持狀態
爲了解決這個問題,HTTP協議經過Cookies來保持狀態,對於圖8中的請求,若是使用Cookies進行狀態控制,則變成了如圖9所示。
經過表單變量保持狀態
除了Cookies以外,還可使用表單變量來保持狀態,好比Asp.net就經過一個叫ViewState的Input=「hidden」的框來保持狀態,好比:
1
|
<
input
type
=
"hidden"
name
=
"__VIEWSTATE"
id
=
"__VIEWSTATE"
value
=
"/wEPDwUKMjA0OTM4MTAwNGRkXUfhlDv1Cs7/qhBlyZROCzlvf5U="
/>
|
這個原理和Cookies大同小異,只是每次請求和響應所附帶的信息變成了表單變量。
經過QueryString保持狀態
這個原理和上述兩種狀態保持方法原理是同樣的,QueryString經過將信息保存在所請求地址的末尾來向服務器傳送信息,一般和表單結合使用,一個典型的QueryString好比:
1
|
www.xxx.com/xxx.aspx?
var
1=value&
var
2=value2
|
本文從一個比較高的視角來看HTTP協議,對於HTTP協議中的細節並無深挖,但對於HTTP大框架有了比較系統的介紹,更多關於HTTP的細節信息,請去Bing或參看相關書籍:-)