一蠢箩、HTTP概況
20世紀(jì)90年代初期拾给,一個(gè)主要的新興應(yīng)用即萬(wàn)維網(wǎng)(World Wide Web)登上了舞臺(tái)弥喉。Web是一個(gè)引起公眾注意的因特網(wǎng)應(yīng)用盒发。Web的應(yīng)用層協(xié)議是超文本傳輸協(xié)議(HTTP)例嘱,它是Web的核心。HTTP由兩個(gè)程序?qū)崿F(xiàn):一個(gè)客戶程序和一個(gè)服務(wù)器程序宁舰∑绰眩客戶程序和服務(wù)器程序運(yùn)行在不同的端系統(tǒng)中,通過(guò)交換HTTP報(bào)文進(jìn)行會(huì)話蛮艰。HTTP會(huì)話定義了這些報(bào)文的結(jié)構(gòu)以及客戶和服務(wù)器進(jìn)行報(bào)文交換的方式腋腮。
Web頁(yè)面(也叫文檔)是由對(duì)象組成的。一個(gè)對(duì)象只是一個(gè)文件壤蚜,諸如一個(gè)HTML文件即寡、一個(gè)JPEG圖形、一個(gè)Java小程序或一個(gè)視頻片段這樣的文件袜刷,且他們可通過(guò)一個(gè)URL地址尋址聪富。多數(shù)Web頁(yè)面含有一個(gè)HTML基本文件以及幾個(gè)引用對(duì)象。例如著蟹,如果一個(gè)Web頁(yè)面包含HTML基本文件和5個(gè)JPEG圖形墩蔓,那么這個(gè)Web頁(yè)面6個(gè)對(duì)象:一個(gè)HTML基本文件加5個(gè)圖形。HTML基本文件通過(guò)對(duì)象的URL地址引用頁(yè)面中的其他對(duì)象萧豆。每個(gè)URL地址由兩部分組成:存放對(duì)象的服務(wù)器主機(jī)名和對(duì)象的路徑名奸披。Web瀏覽器實(shí)現(xiàn)了HTTP的客戶端,Web服務(wù)器實(shí)現(xiàn)了HTTP的服務(wù)器端涮雷,它用于存儲(chǔ)Web對(duì)象源内,每個(gè)對(duì)象由URL尋址。
HTTP定義了Web客戶向Web服務(wù)器請(qǐng)求Web頁(yè)面的方式,以及服務(wù)器向客戶傳送Web頁(yè)面的方式膜钓,其基本思想就是當(dāng)用戶請(qǐng)求一個(gè)Web頁(yè)面(如點(diǎn)擊一個(gè)超鏈接)時(shí)嗽交,瀏覽器向服務(wù)器發(fā)出對(duì)該頁(yè)面中所包含對(duì)象的HTTP請(qǐng)求報(bào)文,服務(wù)器接收到請(qǐng)求并用包含這些對(duì)象的HTTP響應(yīng)報(bào)文進(jìn)行響應(yīng)颂斜。
HTTP使用TCP作為它的支撐運(yùn)輸協(xié)議(而不是在UDP上運(yùn)行)夫壁。HTTP客戶首先發(fā)起一個(gè)與服務(wù)器的TCP連接。一旦連接建立沃疮,該瀏覽器和服務(wù)器進(jìn)程就可以通過(guò)套接字接口訪問(wèn)TCP盒让。客戶向它的套接字接口發(fā)送HTTP請(qǐng)求報(bào)文并從它的套接字接口接收HTTP響應(yīng)報(bào)文司蔬。類(lèi)似的邑茄,服務(wù)器從它的套接字接口接收HTTP請(qǐng)求報(bào)文和向它的套接字接口發(fā)送HTTP響應(yīng)報(bào)文。一旦客戶向他的套接字接口發(fā)送了一個(gè)請(qǐng)求報(bào)文俊啼,該報(bào)文就脫離了客戶控制并進(jìn)入TCP的控制肺缕。TCP為HTTP提供可靠數(shù)據(jù)傳輸服務(wù)。這意味著授帕,一個(gè)客戶進(jìn)程發(fā)出的每個(gè)HTTP請(qǐng)求報(bào)文最終能完整地到達(dá)服務(wù)器同木;類(lèi)似的,服務(wù)器進(jìn)程發(fā)出的每個(gè)HTTP響應(yīng)報(bào)文最終能完整地到達(dá)客戶跛十。
注意到下列現(xiàn)象很重要:服務(wù)器向客戶發(fā)送被請(qǐng)求的文件彤路,而不存儲(chǔ)任何關(guān)于該客戶的狀態(tài)信息。假如某個(gè)特定的客戶在短短的幾秒鐘內(nèi)兩次請(qǐng)求同一個(gè)對(duì)象芥映,服務(wù)器并不會(huì)因?yàn)閯倓倿樵摽蛻籼峁┝嗽搶?duì)象就不再做出反應(yīng)洲尊,而是重新發(fā)送該對(duì)象,就像服務(wù)器已經(jīng)完全忘記不久之前所做過(guò)的事一樣奈偏。因?yàn)镠TTP服務(wù)器并不保存關(guān)于客戶的任何信息颊郎,所以我們說(shuō)HTTP是一個(gè)無(wú)狀態(tài)協(xié)議。
二霎苗、非持續(xù)連接和持續(xù)連接
在許多因特網(wǎng)應(yīng)用程序中,客戶和服務(wù)器在一個(gè)相當(dāng)長(zhǎng)的時(shí)間范圍內(nèi)通信榛做,其中客戶發(fā)出一系列請(qǐng)求并且服務(wù)器對(duì)每個(gè)請(qǐng)求進(jìn)行響應(yīng)唁盏。依據(jù)應(yīng)用程序以及該應(yīng)用程序的使用方式,這一系列請(qǐng)求可以以規(guī)則的間隔周期性的或者間斷性的一個(gè)接一個(gè)發(fā)出检眯。當(dāng)這種客戶-服務(wù)器的交互是經(jīng)TCP進(jìn)行的厘擂,應(yīng)用程序的研制者就要做一個(gè)重要決定,即每個(gè)請(qǐng)求/響應(yīng)對(duì)是經(jīng)一個(gè)單獨(dú)的TCP連接發(fā)送锰瘸,還是所有的請(qǐng)求及其相應(yīng)經(jīng)相同的TCP連接發(fā)送呢刽严?采用前一種方法,該應(yīng)用程序被稱為使用非持續(xù)連接避凝;采用后一種方法舞萄,該應(yīng)用程序被稱為使用持續(xù)連接眨补。如HTTP既能夠使用非持續(xù)連接,也能夠使用持續(xù)連接倒脓。盡管HTTP在默認(rèn)方式下使用持續(xù)連接撑螺,HTTP客戶和服務(wù)器也能配置成非持續(xù)連接。
1.采用非持續(xù)連接的HTTP
我們看看在非持續(xù)連接情況下崎弃,從服務(wù)器向客戶傳送一個(gè)Web頁(yè)面的步驟甘晤。假設(shè)該頁(yè)面含有一個(gè)HTML基本文件和10個(gè)JPEG圖形,并且這11個(gè)對(duì)象位于同一臺(tái)服務(wù)器上饲做。該HTML文件的URL為:http://www.someSchool.edu/someDepartment/home.index线婚。我們看看發(fā)生了什么情況:
- HTTP客戶進(jìn)程在端口號(hào)80發(fā)起一個(gè)到服務(wù)器www.someSchool.edu的TCP連接,該端口號(hào)是HTTP的默認(rèn)端口盆均。在客戶和服務(wù)器上分別有一個(gè)套接字與該連接相關(guān)聯(lián)塞弊。
- HTTP客戶經(jīng)它的套接字向該服務(wù)器發(fā)送一個(gè)HTTP請(qǐng)求報(bào)文。請(qǐng)求報(bào)文中包含了路徑名/someDepartment/home.index缀踪。
- HTTP服務(wù)器進(jìn)程經(jīng)它的套接字接收該請(qǐng)求報(bào)文居砖,從其存儲(chǔ)器(RAM或磁盤(pán))中檢索出對(duì)象http://www.someSchool.edu/someDepartment/home.index,在一個(gè)HTTP響應(yīng)報(bào)文中封裝對(duì)象驴娃,并通過(guò)其套接字向客戶發(fā)送響應(yīng)報(bào)文奏候。
- HTTP服務(wù)器進(jìn)程通知TCP斷開(kāi)該TCP連接。(但是直到TCP確認(rèn)客戶已經(jīng)完整的收到響應(yīng)報(bào)文為止唇敞,它才會(huì)實(shí)際中斷連接蔗草。
- HTTP客戶接收響應(yīng)報(bào)文,TCP連接關(guān)閉疆柔。該報(bào)文指出封裝的對(duì)象是一個(gè)HTML文件咒精,客戶從響應(yīng)報(bào)文中提取出該文件,檢查該HTML文件旷档,得到對(duì)10個(gè)JPEG圖形的引用模叙。
- 對(duì)每個(gè)引用的JPEG圖形對(duì)象重復(fù)前4個(gè)步驟。
上面的步驟舉例說(shuō)明了非持續(xù)連接的使用鞋屈,其中每個(gè)TCP連接在服務(wù)器發(fā)送一個(gè)對(duì)象后關(guān)閉范咨,即該連接并不為其他的對(duì)象而持續(xù)下來(lái)。值得注意的是每個(gè)TCP來(lái)接只傳輸一個(gè)請(qǐng)求報(bào)文和響應(yīng)報(bào)文厂庇。
在上面描述的步驟中渠啊,我們有意沒(méi)有明確客戶獲得這10個(gè)JPEG圖形對(duì)象是使用10個(gè)串行的TCP連接,還是某些JPEG對(duì)象使用了一些并行的TCP連接权旷。事實(shí)上替蛉,用戶能配置現(xiàn)代瀏覽器以控制并行度。在默認(rèn)方式下,大部分瀏覽器打開(kāi)5~10個(gè)并行的TCP連接躲查,而每條連接處理一個(gè)請(qǐng)求響應(yīng)事務(wù)它浅。如果用戶愿意,最大并行連接數(shù)可以設(shè)置為1熙含,這樣10條連接就會(huì)串行建立罚缕。
我們來(lái)簡(jiǎn)單估算一下從客戶請(qǐng)求HTML基本文件起到該客戶收到整個(gè)文件止所花費(fèi)的時(shí)間。為此怎静,我們給出往返時(shí)間(Round-Trip Time邮弹,RTT)的定義,該時(shí)間是指一個(gè)短分組從客戶到服務(wù)器然后再返回客戶所花費(fèi)的時(shí)間蚓聘。RTT包括分組傳播時(shí)延腌乡、分組在中間路由器和交換機(jī)上的排隊(duì)時(shí)延以及分組處理時(shí)延。現(xiàn)在考慮當(dāng)用戶點(diǎn)擊超鏈接時(shí)會(huì)發(fā)生什么現(xiàn)象夜牡。如圖2-7所示与纽,這引起瀏覽器在它和Web服務(wù)器之間發(fā)起一個(gè)TCP連接;這涉及一次“三次握手”過(guò)程塘装。即客戶向服務(wù)器發(fā)送一個(gè)小TCP報(bào)文段急迂,服務(wù)器用一個(gè)小TCP報(bào)文段做出確認(rèn)和響應(yīng),最后蹦肴,客戶向服務(wù)器返回確認(rèn)僚碎。三次握手中前兩個(gè)部分所耗費(fèi)的時(shí)間占用了一個(gè)RTT。完成了三次握手的前兩個(gè)部分后阴幌,客戶結(jié)合三次握手的第三部分(確認(rèn))向該TCP連接發(fā)送一個(gè)HTTP請(qǐng)求報(bào)文勺阐。一旦該請(qǐng)求報(bào)文到達(dá)服務(wù)器,服務(wù)器就在該TCP連接上發(fā)送HTML文件矛双。該HTTP請(qǐng)求/響應(yīng)用去了另一個(gè)RTT渊抽。因此,粗略地將议忽,總的響應(yīng)時(shí)間就是兩個(gè)RTT加上服務(wù)器傳輸HTML文件的時(shí)間懒闷。
2.采用持續(xù)連接的HTTP
非持續(xù)連接有一些缺點(diǎn)。首先栈幸,必須為每一個(gè)請(qǐng)求的對(duì)象建立和維護(hù)一個(gè)全新的連接愤估。對(duì)于每個(gè)這樣的連接,在客戶和服務(wù)器中都要分配TCP的緩沖區(qū)和保持TCP變量侦镇,這給Web服務(wù)器帶來(lái)了嚴(yán)重的負(fù)擔(dān),因?yàn)橐慌_(tái)Web服務(wù)器可能同時(shí)服務(wù)于數(shù)以百計(jì)不同的客戶的請(qǐng)求织阅。第二壳繁,就像我們剛描述的那樣,每一個(gè)對(duì)象經(jīng)受兩倍RTT的交付時(shí)延,即一個(gè)RTT用于創(chuàng)建TCP闹炉,另一個(gè)RTT用于請(qǐng)求和接收一個(gè)對(duì)象蒿赢。
在采用持續(xù)連接的情況下,服務(wù)器在發(fā)送響應(yīng)后保持該TCP連接打開(kāi)渣触。在相同的客戶與服務(wù)器之間的后續(xù)請(qǐng)求和響應(yīng)報(bào)文能夠通過(guò)相同的連接進(jìn)行傳送羡棵。特別是,一個(gè)完整的Web頁(yè)面(上例中的HTML基本文件加上10個(gè)圖形)可以用單個(gè)持續(xù)TCP連接進(jìn)行傳送嗅钻。更有甚者皂冰,位于同一臺(tái)服務(wù)器的多個(gè)Web頁(yè)面在從該服務(wù)器發(fā)送給同一個(gè)客戶時(shí),可以在單個(gè)持續(xù)TCP連接上進(jìn)行养篓。可以一個(gè)接一個(gè)地發(fā)出對(duì)對(duì)象的這些請(qǐng)求秃流,而不必等待對(duì)未決請(qǐng)求(流水線)的回答。一般來(lái)說(shuō)柳弄,如果一條連接經(jīng)過(guò)一定的時(shí)間間隔(一個(gè)可配置的超時(shí)間隔)仍未被使用舶胀,HTTP服務(wù)器就關(guān)閉該連接。HTTP的默認(rèn)模式是使用帶流水線的持續(xù)連接碧注。
三嚣伐、HTTP報(bào)文格式
HTTP報(bào)文有兩種:請(qǐng)求報(bào)文和響應(yīng)報(bào)文。
1.HTTP請(qǐng)求報(bào)文
下面提供了一個(gè)典型的HTTP請(qǐng)求報(bào)文:
GET /somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr
通過(guò)仔細(xì)觀察這個(gè)簡(jiǎn)單的請(qǐng)求報(bào)文萍丐,我們就能知道很多東西轩端。首先,我們看到該報(bào)文是用普通的ASCII文本書(shū)寫(xiě)的碉纺,我們看到該報(bào)文由5行組成船万,每行由一個(gè)回車(chē)和換行符結(jié)束。最后一行后再附加一個(gè)回車(chē)換行符骨田。一個(gè)請(qǐng)求報(bào)文能夠具有更多的行或者至少為一行耿导。請(qǐng)求行的方法字段可以取幾種不同的值,包括GET态贤、POST舱呻、HEAD、PUT和DELETE悠汽。當(dāng)瀏覽器請(qǐng)求一個(gè)對(duì)象時(shí)箱吕,使用GET方法,在URL字段帶有請(qǐng)求對(duì)象的標(biāo)識(shí)柿冲,在本例中茬高,該瀏覽器正在請(qǐng)求對(duì)象/somedir/page.html。其版本字段是自解釋的假抄;在本例中怎栽,瀏覽器實(shí)現(xiàn)的是HTTP/1.1版本±鲡現(xiàn)在我們看看本例的首部行。首部行Host: www.someschool.edu指明了對(duì)象所在的主機(jī)熏瞄。你也許認(rèn)為該首部行是不必要的脚祟,因?yàn)樵谠撝鳈C(jī)中已經(jīng)有一條TCP連接存在了,但是强饮,該首部行提供的信息是Web代理高速緩存所要求的由桌。通過(guò)包含Connection: close首部行,該瀏覽器告訴服務(wù)器不希望麻煩地使用持續(xù)連接邮丰,它要求服務(wù)器在發(fā)送完被請(qǐng)求的對(duì)象后就關(guān)閉這條連接行您。User-agent: 首部行用來(lái)指明用戶代理,即向服務(wù)器發(fā)送請(qǐng)求的瀏覽器類(lèi)型柠座。這里瀏覽器類(lèi)型是Mozilla/5.0邑雅,即Firefox瀏覽器。這個(gè)首部行是有用的妈经,因?yàn)榉?wù)器可以有效地為不同類(lèi)型的用戶代理實(shí)際發(fā)送相同對(duì)象的不同版本淮野。(每個(gè)版本都由相同的URL尋址。)最后吹泡,Accept-language: 首部行表示用戶想得到該對(duì)象的法語(yǔ)版本骤星。如果服務(wù)器中沒(méi)有這樣的對(duì)象的話,服務(wù)器應(yīng)當(dāng)發(fā)送它的默認(rèn)版本爆哑。
接下來(lái)看看如圖2-8所示的一個(gè)請(qǐng)求報(bào)文的通用格式洞难。你可能注意到了在首部行(和附加的回車(chē)和換行)后有一個(gè)“實(shí)體主體”。使用GET方法是實(shí)體主體為空揭朝,而使用POST方法時(shí)才使用該實(shí)體主體队贱。當(dāng)用戶提交表單時(shí),HTTP客戶常常使用POST方法潭袱,例如當(dāng)用戶向搜索引擎提供搜索關(guān)鍵詞時(shí)柱嫌。使用POST報(bào)文時(shí),用戶仍可以向服務(wù)器請(qǐng)求一個(gè)Web頁(yè)面屯换,但Web頁(yè)面的特定內(nèi)容依賴于用戶在表單字段中輸入的內(nèi)容编丘。如果方法字段的值為POST時(shí),則實(shí)體主體中包含的就是用戶在表單字段中的輸入值彤悔。
當(dāng)然嘉抓,如果不提“用表單生成的請(qǐng)求報(bào)文不是必須使用POST方法”這一點(diǎn),那將是失職晕窑。HTML表單經(jīng)常使用GET方法抑片,并在(表單字段中)所請(qǐng)求的URL中包括輸入的數(shù)據(jù)。例如杨赤,一個(gè)表單使用GET方法敞斋,它有兩個(gè)字段级遭,分別填寫(xiě)的是“monkeys”和“bananas”,這樣渺尘,該URL結(jié)構(gòu)為www.somesite.com/animalsearch? monkeys&bananas。
HEAD方法類(lèi)似GET方法说敏。當(dāng)服務(wù)器收到使用HEAD方法的請(qǐng)求時(shí)鸥跟,將會(huì)用一個(gè)HTTP報(bào)文進(jìn)行響應(yīng),但是并不返回請(qǐng)求對(duì)象盔沫。應(yīng)用程序開(kāi)發(fā)者常用HEAD方法進(jìn)行調(diào)試跟蹤医咨。PUT方法常與Web發(fā)行工具聯(lián)合使用,它允許用戶上傳對(duì)象到指定的Web服務(wù)器上指定的路徑(目錄)架诞。PUT也被那些需要向Web服務(wù)器上傳對(duì)象的應(yīng)用程序使用拟淮。DELETE方法允許用戶或者應(yīng)用程序刪除Web服務(wù)器上的對(duì)象。
2.HTTP響應(yīng)報(bào)文
下面我們提供了一條典型的HTTP響應(yīng)報(bào)文谴忧。該響應(yīng)報(bào)文可以是對(duì)剛剛討論的例子中請(qǐng)求報(bào)文的響應(yīng)很泊。
HTTP/1.1 200 OK
Connection: close
Date: Tue, 09 Aug 2011 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 09 Aug 2011 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html
(data data data data data ...)
我們仔細(xì)看這個(gè)響應(yīng)報(bào)文。實(shí)體主體部分是報(bào)文的主要部分沾谓,即它包含了所請(qǐng)求的對(duì)象本身(表示為data data data data data ...)委造。我們現(xiàn)在來(lái)看看首部行。服務(wù)器用Connection:close首部行告訴客戶均驶,發(fā)送完報(bào)文后將關(guān)閉該TCP連接昏兆。Date:首部行指示服務(wù)器產(chǎn)生并發(fā)送該響應(yīng)報(bào)文的日期和時(shí)間。值得一提的是妇穴,這個(gè)時(shí)間不是指對(duì)象創(chuàng)建或者最后修改的時(shí)間爬虱;而是服務(wù)器從它的文件系統(tǒng)中檢索到該對(duì)象,插入到響應(yīng)報(bào)文腾它,并發(fā)送響應(yīng)報(bào)文的時(shí)間跑筝。Server:首部行指示該報(bào)文是由一臺(tái)Apache Web服務(wù)器產(chǎn)生的,它類(lèi)似于HTTP請(qǐng)求報(bào)文中的User-agent:首部行携狭,Last-Modified:首部行指示了對(duì)象創(chuàng)建或者最后修改的日期和時(shí)間继蜡。Last-Modified:首部行對(duì)極可能在本地客戶也可能在網(wǎng)絡(luò)緩存服務(wù)器(代理服務(wù)器)上的對(duì)象緩存來(lái)說(shuō)非常重要。Content-Length:首部行知識(shí)了被發(fā)送對(duì)象中的字節(jié)數(shù)逛腿。Content-Type:首部行指示了實(shí)體主體中的對(duì)象是HTML文本稀并。(該對(duì)象類(lèi)型應(yīng)該正式地由Content-Type:首部行而不是用文件擴(kuò)展名來(lái)指示。)
看過(guò)一個(gè)例子后单默,我們?cè)賮?lái)查看響應(yīng)報(bào)文的通用格式(如圖2-9所示)碘举。我們補(bǔ)充說(shuō)明一下?tīng)顟B(tài)碼和它們對(duì)應(yīng)的短語(yǔ)。狀態(tài)碼及其相應(yīng)的短語(yǔ)指示了請(qǐng)求的結(jié)果搁廓。一些常見(jiàn)的狀態(tài)碼和相關(guān)的短語(yǔ)包括:
- 200 OK:請(qǐng)求成功引颈,信息在返回的響應(yīng)報(bào)文中耕皮。
- 301 Moved Permanently:請(qǐng)求的對(duì)象已經(jīng)被永久轉(zhuǎn)移了,新的URL定義在響應(yīng)報(bào)文的Location:首部行中蝙场。**客戶軟件將自動(dòng)獲取新的URL凌停。
- 400 Bad Request:一個(gè)通用差錯(cuò)代碼,指示該請(qǐng)求不能被服務(wù)器理解售滤。
- 404 Not Found:被請(qǐng)求的文檔不在服務(wù)器上罚拟。
- 505 HTTP Version Not Supported:服務(wù)器不支持請(qǐng)求報(bào)文使用的HTTP協(xié)議版本。
你想看一下真正的HTTP響應(yīng)報(bào)文嗎完箩?很容易做到赐俗。首先用Telnet登錄到你喜歡的Web服務(wù)器上,接下來(lái)輸入一個(gè)只有一行的請(qǐng)求報(bào)文去請(qǐng)求放在該服務(wù)器上的某些對(duì)象弊知。
在linux終端輸入完telnet www.baidu.com 80后阻逮,會(huì)是下面這種情況:
然后按下ctrl + ]呼出telnet命令行出現(xiàn)下面這種情況:
先按下回車(chē)鍵,再輸入HTTP請(qǐng)求秩彤,最終得到HTTP響應(yīng)如下:
在telnet命令行上輸入quit退出telnet叔扼,如下圖: