国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
了解WWW服務(wù)與HTTP協(xié)議
當(dāng)我們想瀏覽一個(gè)網(wǎng)站的時(shí)候,只要在瀏覽器的地址欄里輸入網(wǎng)站的地址就可以了,例如:www.microsoft.com,但是在瀏覽器的地址欄里面出現(xiàn)的卻是:http://www.microsoft.com,你知道為什么會多出一個(gè)“http”嗎?
一、HTTP協(xié)議是什么
我們在瀏覽器的地址欄里輸入的網(wǎng)站地址叫做URL(UniformResourceLocator,統(tǒng)一資源定位符)。就像每家每戶都有一個(gè)門牌地址一樣,每個(gè)網(wǎng)頁也都有一個(gè)Internet地址。當(dāng)你在瀏覽器的地址框中輸入一個(gè)URL或是單擊一個(gè)超級鏈接時(shí),URL就確定了要瀏覽的地址。瀏覽器通過超文本傳輸協(xié)議(HTTP),將Web服務(wù)器上站點(diǎn)的網(wǎng)頁代碼提取出來,并翻譯成漂亮的網(wǎng)頁。因此,在我們認(rèn)識HTTP之前,有必要先弄清楚URL的組成,例如:http://www.microsoft.com/china/index.htm。它的含義如下:
1.http://:代表超文本傳輸協(xié)議,通知microsoft.com服務(wù)器顯示W(wǎng)eb頁,通常不用輸入;
2.www:代表一個(gè)Web(萬維網(wǎng))服務(wù)器;
3.Microsoft.com/:這是裝有網(wǎng)頁的服務(wù)器的域名,或站點(diǎn)服務(wù)器的名稱;
4.China/:為該服務(wù)器上的子目錄,就好像我們的文件夾;
5.Index.htm:index.htm是文件夾中的一個(gè)HTML文件(網(wǎng)頁)。
我們知道,Internet的基本協(xié)議是TCP/IP協(xié)議,然而在TCP/IP模型最上層的是應(yīng)用層(Applicationlayer),它包含所有高層的協(xié)議。高層協(xié)議有:文件傳輸協(xié)議FTP、電子郵件傳輸協(xié)議SMTP、域名系統(tǒng)服務(wù)DNS、網(wǎng)絡(luò)新聞傳輸協(xié)議NNTP和HTTP協(xié)議等。
HTTP協(xié)議(HypertextTransferProtocol,超文本傳輸協(xié)議)是用于從WWW服務(wù)器傳輸超文本到本地瀏覽器的傳送協(xié)議。它可以使瀏覽器更加高效,使網(wǎng)絡(luò)傳輸減少。它不僅保證計(jì)算機(jī)正確快速地傳輸超文本文檔,還確定傳輸文檔中的哪一部分,以及哪部分內(nèi)容首先顯示(如文本先于圖形)等。這就是你為什么在瀏覽器中看到的網(wǎng)頁地址都是以“http://”開頭的原因。
自WWW誕生以來,一個(gè)多姿多彩的資訊和虛擬的世界便出現(xiàn)在我們眼前,可是我們怎么能夠更加容易地找到我們需要的資訊呢?當(dāng)決定使用超文本作為WWW文檔的標(biāo)準(zhǔn)格式后,于是在1990年,科學(xué)家們立即制定了能夠快速查找這些超文本文檔的協(xié)議,即HTTP協(xié)議。經(jīng)過幾年的使用與發(fā)展,得到不斷的完善和擴(kuò)展,目前在WWW中使用的是HTTP/1.0的第六版。
二、HTTP是怎樣工作的
既然我們明白了URL的構(gòu)成,那么HTTP是怎么工作呢?我們接下來就要討論這個(gè)問題。
由于HTTP協(xié)議是基于請求/響應(yīng)范式的(相當(dāng)于客戶機(jī)/服務(wù)器)。一個(gè)客戶機(jī)與服務(wù)器建立連接后,發(fā)送一個(gè)請求給服務(wù)器,請求方式的格式為:統(tǒng)一資源標(biāo)識符(URL)、協(xié)議版本號,后邊是MIME信息包括請求修飾符、客戶機(jī)信息和可能的內(nèi)容。服務(wù)器接到請求后,給予相應(yīng)的響應(yīng)信息,其格式為一個(gè)狀態(tài)行,包括信息的協(xié)議版本號、一個(gè)成功或錯(cuò)誤的代碼,后邊是MIME信息包括服務(wù)器信息、實(shí)體信息和可能的內(nèi)容。
許多HTTP通訊是由一個(gè)用戶代理初始化的并且包括一個(gè)申請?jiān)谠捶?wù)器上資源的請求。最簡單的情況可能是在用戶代理和服務(wù)器之間通過一個(gè)單獨(dú)的連接來完成。在Internet上,HTTP通訊通常發(fā)生在TCP/IP連接之上。缺省端口是TCP80,但其它的端口也是可用的。但這并不預(yù)示著HTTP協(xié)議在Internet或其它網(wǎng)絡(luò)的其它協(xié)議之上才能完成。HTTP只預(yù)示著一個(gè)可靠的傳輸。
這個(gè)過程就好像我們打電話訂貨一樣,我們可以打電話給商家,告訴他我們需要什么規(guī)格的商品,然后商家再告訴我們什么商品有貨,什么商品缺貨。這些,我們是通過電話線用電話聯(lián)系(HTTP是通過TCP/IP),當(dāng)然我們也可以通過傳真,只要商家那邊也有傳真。
以上簡要介紹了HTTP協(xié)議的宏觀運(yùn)作方式,下面介紹一下HTTP協(xié)議的內(nèi)部操作過程。
在WWW中,“客戶”與“服務(wù)器”是一個(gè)相對的概念,只存在于一個(gè)特定的連接期間,即在某個(gè)連接中的客戶在另一個(gè)連接中可能作為服務(wù)器。基于HTTP協(xié)議的客戶/服務(wù)器模式的信息交換過程,它分四個(gè)過程:建立連接、發(fā)送請求信息、發(fā)送響應(yīng)信息、關(guān)閉連接。這就好像上面的例子,我們電話訂貨的全過程。
其實(shí)簡單說就是任何服務(wù)器除了包括HTML文件以外,還有一個(gè)HTTP駐留程序,用于響應(yīng)用戶請求。你的瀏覽器是HTTP客戶,向服務(wù)器發(fā)送請求,當(dāng)瀏覽器中輸入了一個(gè)開始文件或點(diǎn)擊了一個(gè)超級鏈接時(shí),瀏覽器就向服務(wù)器發(fā)送了HTTP請求,此請求被送往由IP地址指定的URL。駐留程序接收到請求,在進(jìn)行必要的操作后回送所要求的文件。在這一過程中,在網(wǎng)絡(luò)上發(fā)送和接收的數(shù)據(jù)已經(jīng)被分成一個(gè)或多個(gè)數(shù)據(jù)包(packet),每個(gè)數(shù)據(jù)包包括:要傳送的數(shù)據(jù);控制信息,即告訴網(wǎng)絡(luò)怎樣處理數(shù)據(jù)包。TCP/IP決定了每個(gè)數(shù)據(jù)包的格式。如果事先不告訴你,你可能不會知道信息被分成用于傳輸和再重新組合起來的許多小塊。
也就是說商家除了擁有商品之外,它也有一個(gè)職員在接聽你的電話,當(dāng)你打電話的時(shí)候,你的聲音轉(zhuǎn)換成各種復(fù)雜的數(shù)據(jù),通過電話線傳輸?shù)綄Ψ降碾娫挋C(jī),對方的電話機(jī)又把各種復(fù)雜的數(shù)據(jù)轉(zhuǎn)換成聲音,使得對方商家的職員能夠明白你的請求。這個(gè)過程你不需要明白聲音是怎么轉(zhuǎn)換成復(fù)雜的數(shù)據(jù)的。
了解WWW服務(wù)與HTTP協(xié)議
在前一篇文章里,我們介紹了網(wǎng)絡(luò)應(yīng)用和網(wǎng)絡(luò)協(xié)議的一些基礎(chǔ)知識,現(xiàn)在,讓我們來了解一下WWW服務(wù)應(yīng)用和HTTP網(wǎng)絡(luò)協(xié)議。
歷史上,先后問世了多個(gè)具有重大社會影響的電子通信技術(shù)。第一個(gè)這樣的技術(shù)是19世紀(jì)70年代發(fā)明的電話。電話使得不在同一物理位置的兩人得以實(shí)時(shí)地口頭交流。它對社會有重大的影響——有好的也有壞的。下一個(gè)電子通信技術(shù)是20世紀(jì)20年代及30年代問世的廣播收音機(jī)/電視機(jī)。廣播收音機(jī)/電視機(jī)使得人們能收聽收視大量的音頻和視頻信息。它對社會同樣有重大的影響——有好的也有壞的。改變了人們的生活與工作方式的第三個(gè)重大通信技術(shù)是web。web最吸引用戶的也許是它的隨選(on demand)操作性。用戶只在想要時(shí)收到所要的東西。這一點(diǎn)不同于廣播收音機(jī)/電視機(jī)。廣播收音機(jī)/電視機(jī)的用戶是在其內(nèi)容供應(yīng)商播出內(nèi)容期間被迫收聽收視。除了隨選操作性,Web還有許多大家喜愛的其他精彩特性。任何個(gè)人都可以極其容易地在Web上公布任何信息;任何人都可能以極低的成本成為發(fā)行人。超鏈接和搜索引擎幫助我們在Web站點(diǎn)的海洋中導(dǎo)航。圖形和動畫刺激著我們的感官。表單、Java小應(yīng)用程序、Activex控件以及其他許多設(shè)備使得我們能與Web頁面和站點(diǎn)交互。Web還越來越普遍地提供存放在因特網(wǎng)中的、可隨選訪問(即點(diǎn)播)的大量音頻和視頻材料的菜單接口。
HTTP概貌
Web的應(yīng)用層協(xié)議HTTP是Web的核心。HTTP在Web的客戶程序和服務(wù)器程序中得以實(shí)現(xiàn)。運(yùn)行在不同端系統(tǒng)上的客戶程序和服務(wù)器程序通過交換HTTP消息彼此交流。HTTP定義這些消息的結(jié)構(gòu)以及客戶和服務(wù)器如何交換這些消息。在詳細(xì)解釋HTTP之前,我們先來回顧一些web中的術(shù)語。
Web頁面(web page,也稱為文檔)由多個(gè)對象構(gòu)成。對象(object)僅僅是可由單個(gè)URL尋址的文件,例如HTML文件、JPG圖像、GIF圖像、JAVA小應(yīng)用程序、語音片段等。大多數(shù)Web頁面由單個(gè)基本HIML文件和若干個(gè)所引用的對象構(gòu)成。例如,如果一個(gè)Web頁面包含HTML文本和5個(gè)JPEG圖像,那么它由6個(gè)對象構(gòu)成,即基本H1ML文件加5個(gè)圖像。基本HTML文件使用相應(yīng)的URL來引用本頁面的其他對象。每個(gè)URL由存放該對象的服務(wù)器主機(jī)名和該對象的路徑名兩部分構(gòu)成。例如,在如下的URL中:
www.chinaitlab.com/urlpath/picture.qif
www.chinaitlab.com是一個(gè)主機(jī)名,/urlpath/picture.qif是一個(gè)路徑名。瀏覽器是web的用戶代理,它顯示所請求的Web頁面,并提供大量的導(dǎo)航與配置特性。Web瀏覽器還實(shí)現(xiàn)HTTP的客戶端,因此在web上下文中,我們會從進(jìn)程意義上互換使用“瀏覽器”和“客戶”兩詞。流行的Web瀏覽器有Netscape Communicator,firefox和微軟的IE等。Web服務(wù)器存放可由URL尋址的Web對象。web服務(wù)器還實(shí)現(xiàn)HTTP的服務(wù)器端。流行的Web服務(wù)器有Apache、微軟的IIS以及Netscape Enterprise Server。Netcraft提供了web服務(wù)器的概要剖析[Netcrft 2000]。
HTTP定義Web客戶(即瀏覽器)如何從web服務(wù)器請求Web頁面,以及服務(wù)器如何把Web頁面?zhèn)魉徒o客戶。下圖展示了這種請求—響應(yīng)行為。當(dāng)用戶請求一個(gè)Web頁面(譬如說點(diǎn)擊某個(gè)超鏈接)時(shí),瀏覽器把請求該頁面中各個(gè)對象的HTTP請求消息發(fā)送給服務(wù)器。服務(wù)器收到請求后,以運(yùn)送含有這些對象HTTP響應(yīng)消息作為響應(yīng)。到1997年底,基本上所有的瀏覽器和Web服務(wù)器軟件都實(shí)現(xiàn)了在RFC 1945中定義的HTTP/1.0版本。1998年初,一些Web服務(wù)器軟件和瀏覽器軟件開始實(shí)現(xiàn)在RFC 2616中定義的HTTP/1.1版本。H1TP/1.1與HTTP/1.0后向兼容;運(yùn)行1.1版本的web服務(wù)器可以與運(yùn)行1.0版本的瀏覽器“對話”,運(yùn)行1.1版本的瀏覽器也可以與運(yùn)行1.0版本的Web服務(wù)器“對話”。
圖1 HTTP請求與響應(yīng)行為
HTTP/1.0和HTTP/1.1都把TCP作為底層的傳輸協(xié)議。HTTP客戶首先發(fā)起建立與服務(wù)器TCP連接。一旦建立連接,瀏覽器進(jìn)程和服務(wù)器進(jìn)程就可以通過各自的套接字來訪問TCP。如前所述,客戶端套接字是客戶進(jìn)程和TCP連接之間的“門”,服務(wù)器端套接字是服務(wù)器進(jìn)程和同一TCP連接之間的“門”??蛻敉约旱奶捉幼职l(fā)送HTTP請求消息,也從自己的套接字接收HTTP響應(yīng)消息。類似地,服務(wù)器從自己的套接字接收HTTP請求消息,也往自己的套接字發(fā)送HTTP響應(yīng)消息??蛻艋蚍?wù)器一旦把某個(gè)消息送入各自的套接字,這個(gè)消息就完全落入TCP的控制之中。TCP給HTTP提供一個(gè)可靠的數(shù)據(jù)傳輸服務(wù);這意味著由客戶發(fā)出的每個(gè)HTTP請求消息最終將無損地到達(dá)服務(wù)器,由服務(wù)器發(fā)出的每個(gè)HTTP響應(yīng)消息最終也將無損地到達(dá)客戶。我們可從中看到分層網(wǎng)絡(luò)體系結(jié)構(gòu)的一個(gè)明顯優(yōu)勢——HTTP不必?fù)?dān)心數(shù)據(jù)會丟失,也無需關(guān)心TCP如何從數(shù)據(jù)的丟失和錯(cuò)序中恢復(fù)出來的細(xì)節(jié)。這些是TCP和協(xié)議棧中更低協(xié)議層的任務(wù)。
TCP還使用一個(gè)擁塞控制機(jī)制。該機(jī)制迫使每個(gè)新的TCP連接一開始以相對緩慢的速率傳輸數(shù)據(jù),然而只要網(wǎng)絡(luò)不擁塞,每個(gè)連接可以迅速上升到相對較高的速率。這個(gè)慢速傳輸?shù)某跏茧A段稱為緩啟動(slow start)。
需要注意的是,在向客戶發(fā)送所請求文件的同時(shí),服務(wù)器并沒有存儲關(guān)于該客戶的任何狀態(tài)信息。即便某個(gè)客戶在幾秒鐘內(nèi)再次請求同一個(gè)對象,服務(wù)器也不會響應(yīng)說:自己剛剛給它發(fā)送了這個(gè)對象。相反,服務(wù)器重新發(fā)送這個(gè)對象,因?yàn)樗呀?jīng)徹底忘記早先做過什么。既然HTTP服務(wù)器不維護(hù)客戶的狀態(tài)信息,我們于是說HTTP是一個(gè)無狀態(tài)的協(xié)議(stateless protocol)。
非持久連接和持久連接
HTTP既可以使用非持久連接(nonpersistent connection),也可以使用持久連接(persistent connection)。HTTP/1.0使用非持久連接,HTTP/1.1默認(rèn)使用持久連接。
非持久連接
讓我們查看一下非持久連接情況下從服務(wù)器到客戶傳送一個(gè)Web頁面的步驟。假設(shè)該貝面由1個(gè)基本HTML文件和10個(gè)JPEG圖像構(gòu)成,而且所有這些對象都存放在同一臺服務(wù)器主機(jī)中。 再假設(shè)該基本HTML文件的URL為:www.chinaitlab.com/somepath/index.html。
下面是具體步騾:
1.HTTP客戶初始化一個(gè)與服務(wù)器主機(jī)www.chinaitlab.com中的HTTP服務(wù)器的TCP連接。HTTP服務(wù)器使用默認(rèn)端口號80監(jiān)聽來自HTTP客戶的連接建立請求。
2.HTTP客戶經(jīng)由與TCP連接相關(guān)聯(lián)的本地套接字發(fā)出—個(gè)HTTP請求消息。這個(gè)消息中包含路徑名/somepath/index.html。
3.HTTP服務(wù)器經(jīng)由與TCP連接相關(guān)聯(lián)的本地套接字接收這個(gè)請求消息,再從服務(wù)器主機(jī)的內(nèi)存或硬盤中取出對象/somepath/index.html,經(jīng)由同一個(gè)套接字發(fā)出包含該對象的響應(yīng)消息。
4.HTTP服務(wù)器告知TCP關(guān)閉這個(gè)TCP連接(不過TCP要到客戶收到剛才這個(gè)響應(yīng)消息之后才會真正終止這個(gè)連接)。
5.HTTP客戶經(jīng)由同一個(gè)套接字接收這個(gè)響應(yīng)消息。TCP連接隨后終止。該消息標(biāo)明所封裝的對象是一個(gè)HTML文件??蛻魪闹腥〕鲞@個(gè)文件,加以分析后發(fā)現(xiàn)其中有10個(gè)JPEG對象的引用。
6.給每一個(gè)引用到的JPEG對象重復(fù)步騾1-4。
瀏覽器在接收web頁面的同時(shí)把它顯示給用戶。不同的瀏覽器可能會以略有不同的方式解釋(也就是向用戶顯示)同一個(gè)web頁面。HTTP與客戶如何解釋W(xué)eb頁面沒有任何關(guān)系,其規(guī)范([RFC 1945]和[RFC 2616I)僅僅定義HTTP客戶程序和服務(wù)器程序之間的通信協(xié)議。
上述步驟之所以稱為使用非持久連接,原因是每次服務(wù)器發(fā)出一個(gè)對象后,相應(yīng)的TCP連接就被關(guān)閉,也就是說每個(gè)連接都沒有持續(xù)到可用于傳送其他對象。每個(gè)TCP連接只用于傳輸一個(gè)請求消息和一個(gè)響應(yīng)消息。就上述例子而言,用戶每請求一次那個(gè)web頁面,就產(chǎn)生11個(gè)TCP連接。
在上述步騾中,我們有意不說清客戶是通過10個(gè)串行的TCP連接先后取得所有JPEG對象,還是通過并行的TCP連接同時(shí)取得其中某些JPEG對象。實(shí)際上,現(xiàn)今的瀏覽器允許用戶通過配置來控制并行連接的程度。大多數(shù)瀏覽器默認(rèn)可以打開5到10個(gè)并行的TCP連接,每個(gè)連接處理一個(gè)請求—響應(yīng)事務(wù)。用戶要是喜歡,可以把最大并行連接數(shù)設(shè)為l,那樣的話這10個(gè)連接是串行地建立的。我們將在第3章看到,使用并行連接可以縮短響應(yīng)時(shí)間。
繼續(xù)介紹之前,先估算一下從客戶請求基本HTML文件到它收到該文件所經(jīng)歷的時(shí)間。為此我們定義往返時(shí)間(round trip time,簡稱RTT),它是一個(gè)小分組從客戶主機(jī)游動到服務(wù)器主機(jī)再返回客戶主機(jī)所花的時(shí)間。RTT包括分組傳播延遲、在中間路由器和交換機(jī)土的分組排隊(duì)延遲以及分組處理延遲。下面考慮用戶點(diǎn)擊某個(gè)超鏈接時(shí)會發(fā)生什么。用戶的點(diǎn)擊導(dǎo)致瀏覽器發(fā)起建立一個(gè)與Web服務(wù)器的TCP連接;這里涉及·—次“三次握手”過程——首先是客戶向服務(wù)器發(fā)送一個(gè)小的冗余消息,接著是服務(wù)器向客戶確認(rèn)并響應(yīng)以一個(gè)小的TCP消息,最后是客戶向服務(wù)器回確認(rèn)。三次握手過程的前兩次結(jié)束時(shí),流逝的時(shí)間為1個(gè)RTT。此時(shí)客戶把HTTP請求消息發(fā)送到TCP連接中,客戶接著把三次握手過程最后一次中的確認(rèn)捎帶在包含這個(gè)消息的數(shù)據(jù)分節(jié)中發(fā)送以去。服務(wù)器收到來自TCP連接的請求消息后,把相應(yīng)的HTML文件發(fā)送到TCP連接中,服務(wù)器接著把對早先收到的客戶請求的確認(rèn)捎帶在包含該HTML文件的數(shù)據(jù)分節(jié)中發(fā)送出去。這個(gè)HTTP請求順應(yīng)交互也花去1個(gè)RTT時(shí)間。因此,總的響應(yīng)時(shí)間粗略地算是2個(gè)RTT加上服務(wù)器發(fā)送這個(gè)HTMI文件的時(shí)間。
持久連接
非持久連接有些缺點(diǎn)。首先,客戶得為每個(gè)待請求的對象建立并維護(hù)一個(gè)新的連接。對于每個(gè)這樣的連接,TCP得在客戶端和服務(wù)器端分配TCP緩沖區(qū),并維持TCP變量。對于有可能同時(shí)為來自數(shù)百個(gè)不同客戶的請求提供服務(wù)的web服務(wù)器來說,這會嚴(yán)重增加其負(fù)擔(dān)。其次,如前所述,每個(gè)對象都有2個(gè)RTT的響應(yīng)延長——一個(gè)RTT用于建立TCP連接,另—個(gè)RTT用于請求和接收對象。最后,每個(gè)對象都遭受TCP緩啟動,因?yàn)槊總€(gè)TCP連接都起始于緩啟動階段。不過并行TCP連接的使用能夠部分減輕RTT延遲和緩啟動延遲的影響。
在持久連接情況下,服務(wù)器在發(fā)出響應(yīng)后讓TCP連接繼續(xù)打開著。同一對客戶/服務(wù)器之間的后續(xù)請求和響應(yīng)可以通過這個(gè)連接發(fā)送。整個(gè)Web頁面(上例中為包含一個(gè)基本HTMLL文件和10個(gè)圖像的頁面)自不用說可以通過單個(gè)持久TCP連接發(fā)送:甚至存放在同一個(gè)服務(wù)器中的多個(gè)web頁面也可以通過單個(gè)持久TCP連接發(fā)送。通常,HTTP服務(wù)器在某個(gè)連接閑置一段特定時(shí)間后關(guān)閉它,而這段時(shí)間通常是可以配置的。持久連接分為不帶流水線(without pipelining)和帶流水線(with pipelining)兩個(gè)版本。如果是不帶流水線的版本,那么客戶只在收到前一個(gè)請求的響應(yīng)后才發(fā)出新的請求。這種情況下,web頁面所引用的每個(gè)對象(上例中的10個(gè)圖像)都經(jīng)歷1個(gè)RTT的延遲,用于請求和接收該對象。與非持久連接2個(gè)RTT的延遲相比,不帶流水線的持久連接已有所改善,不過帶流水線的持久連接還能進(jìn)一步降低響應(yīng)延遲。不帶流水線版本的另一個(gè)缺點(diǎn)是,服務(wù)器送出一個(gè)對象后開始等待下一個(gè)請求,而這個(gè)新請求卻不能馬上到達(dá)。這段時(shí)間服務(wù)器資源便閑置了。
HTTP/1.1的默認(rèn)模式使用帶流水線的持久連接。這種情況下,HTTP客戶每碰到一個(gè)引用就立即發(fā)出一個(gè)請求,因而HTTP客戶可以一個(gè)接一個(gè)緊挨著發(fā)出各個(gè)引用對象的請求。服務(wù)器收到這些請求后,也可以一個(gè)接一個(gè)緊挨著發(fā)出各個(gè)對象。如果所有的請求和響應(yīng)都是緊挨著發(fā)送的,那么所有引用到的對象一共只經(jīng)歷1個(gè)RTT的延遲(而不是像不帶流水線的版本那樣,每個(gè)引用到的對象都各有1個(gè)RTT的延遲)。另外,帶流水線的持久連接中服務(wù)器空等請求的時(shí)間比較少。與非持久連接相比,持久連接(不論是否帶流水線)除降低了1個(gè)RTT的響應(yīng)延遲外,緩啟動延遲也比較小。其原因在于既然各個(gè)對象使用同一個(gè)TCP連接,服務(wù)器發(fā)出第一個(gè)對象后就不必再以一開始的緩慢速率發(fā)送后續(xù)對象。相反,服務(wù)器可以按照第一個(gè)對象發(fā)送完畢時(shí)的速率開始發(fā)送下一個(gè)對象。
HTTP消息格式
HTTP規(guī)范1.0[RPcl945]和1.1[RFC 2616]定義了HTTP消息的格式。HTTP消息分為請求消息和響應(yīng)稍息兩類。下面我們分別進(jìn)行介紹。
HTTP請求消息
下面是一個(gè)典型的HTTP請求消息:
GET /somedir/page.html H7TP/1.1
Host:www.chinaitlab.com
Connection:close
User-agent:Mozilla/4.0
Accept-language:zh-cn
(額外的回車符和換行符)
仔細(xì)檢查這個(gè)簡單的請求消息,我們可從中學(xué)到不少東西。首先,這個(gè)消息是用普通的ASCII文本書寫的。其次,這個(gè)消息共有5行(每行以一個(gè)回車符和一個(gè)換行符結(jié)束),最后一行后面還有額外的一個(gè)回車特和換行符。當(dāng)然,一個(gè)請求消息可以不止這么多行,也可以僅僅只有一行。該請求消息的第一行稱為請求行(request line),后續(xù)各行都稱為頭部行(header)。請求行有3個(gè)寧段:方法字段、URL字段、HTTP版本宇段。方法字段有若干個(gè)值可供選擇,包括GET、POST和HEAD。HTTP請求消息絕大多數(shù)使用GET方法,這是瀏覽器用來請求對象的方法,所請求的對象就在URL字段中標(biāo)識。本例表明瀏覽器在請求對象/somedir/page.html。版本字段是不言自明的;本例中瀏覽器實(shí)現(xiàn)的是HTTP/1.1版本。
現(xiàn)在看一下本例中的各個(gè)頭部行。頭部行Host:www.chinaitlab.com定存放所請求對象的主機(jī)。請求消息中包含頭部Connection:close是在告知服務(wù)器本瀏覽器不想使用持久連接;服務(wù)器發(fā)出所請求的對象后應(yīng)關(guān)閉連接。盡管產(chǎn)生這個(gè)請求消息的瀏覽器實(shí)現(xiàn)的是HTTP/1.1版本,它還是不想使用持久連接。User-agent頭部行指定用戶代理,也就是產(chǎn)生當(dāng)前請求的瀏覽器的類型。本例的用戶代理是Mozilla/4.0,它是Nelscape瀏覽器的一個(gè)版本。這個(gè)頭部行很有用,因?yàn)榉?wù)器實(shí)際上可以給不同類型的用戶代理發(fā)送同一個(gè)對象的不同版本(這些不同版本位用同一個(gè)URL尋址)。最后,Accept-languag:頭部行指出要是所請求對象有簡體中文版本,那么用戶寧愿接收這個(gè)版本;如果沒有這個(gè)語言版本,那么服務(wù)器應(yīng)該發(fā)送其默認(rèn)版本。Accept-languag:僅僅是HTTP的眾多內(nèi)容協(xié)商頭部之一。
我們接著看一下下圖所示的請求消息的一般格式。
圖2:HTTP請求格式
上面的請求消息例子符合這個(gè)格式,不過一般格式中還有一個(gè)位于各個(gè)頭部(及額外的回車符和換行符)之后的“附屬體”(毗叮body)。附屬體不在GET方法中使用,而是在POST方法中使用。POST方法適用于需由用戶填寫表單的場合,如往google搜索引擎中填入待搜索的詞。用戶提交表單后,瀏覽器就像用戶點(diǎn)擊了超鏈接那樣仍然從服務(wù)器請求一個(gè)Web頁面,不過該頁面的具體內(nèi)容卻取決于用戶填寫在表單各個(gè)字段中的值。如果瀏覽器使用POST方法提出該請求,那么請求消息附屬體中包含的是用戶填寫在表單各個(gè)字段中的值。與GET方法類似的是HEAD方法,兩者的差別只是服務(wù)器在對HEAD方法的響應(yīng)消息中去掉了所請求的對象,其他內(nèi)容則與對GET方法的響應(yīng)消息一樣。HEAD方法通常用于HTTP服務(wù)器軟件開發(fā)人員進(jìn)行調(diào)試。
HTTP響應(yīng)消息
下面是一個(gè)典型的HTTP響應(yīng)消息:
HTTP/1.1 200 0K
Connectlon:close
Date: Thu, 13 Oct 2005 03:17:33 GMT
Server: Apache/2.0.54 (Unix)
Last—Nodified:Mon,22 Jun 1998 09;23;24 GMT
Content—Length:682l
Content—Type:text/html
(數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù)…………)
這個(gè)響應(yīng)消息分為3部分:1個(gè)起始的狀態(tài)行(status line),6個(gè)頭部行、1個(gè)包含所請求對象本身的附屬體。狀態(tài)行有3個(gè)字段:協(xié)議版本字段、狀態(tài)碼字段、原因短語字段。本例的狀態(tài)行表明,服務(wù)器使用HTTP/1.1版本,響應(yīng)過程完全正常(也就是說服務(wù)器找到了所請求的對象,并正在發(fā)送)。
現(xiàn)在看一下本例中的各個(gè)頭部行。服務(wù)器使用Connectlon:close頭部行告知客戶自己將在發(fā)送完本消息后關(guān)閉TCP連接。Date:頭部行指出服務(wù)器創(chuàng)建并發(fā)送本響應(yīng)消息的日期和時(shí)間。注意,這并不是對象本身的創(chuàng)建時(shí)間或最后修改時(shí)間,而是服務(wù)器把該對象從其文件系統(tǒng)中取出,插入響應(yīng)消息中發(fā)送出去的時(shí)間。Server:頭部行指出本消息是由Apache服務(wù)器產(chǎn)生的;它與HTTP請求消息中的User-agent:頭部行類似。Last—Nodified:頭部行指出對象本身的創(chuàng)建或最后修改日期或時(shí)間。Last—Nodified:頭部對于對象的高速緩存至關(guān)重要,且不論這種高速緩存是發(fā)生在本地客戶主機(jī)上還是發(fā)生在網(wǎng)絡(luò)高速緩存服務(wù)器主機(jī)(也就是代理服務(wù)器主機(jī))上。Content—Length:頭部行指出所發(fā)送對象的字節(jié)數(shù)。Content—Type:頭部行指出包含在附屬體中的對象是HTML文本。對象的類型是由Content—Type:頭部而不是由文件擴(kuò)展名正式指出的。
注意,如果服務(wù)器收到一個(gè)HTTP/1.0的請求,那么它即使是一個(gè)HTTP/1.1服務(wù)器,也不會使用持久連接。相反,這樣的HTTP/1.1服務(wù)器會在發(fā)出所請求的對象后關(guān)閉TCP連接。這么做是必要的,因?yàn)镠TTP/1.0客戶期待服務(wù)器馬上關(guān)閉連接。
我們接著看一下如下圖所示的響應(yīng)消息的一般格式。前面的響應(yīng)消息例子完全符合這個(gè)格式。響應(yīng)消息中的狀態(tài)碼和原因短語指示相應(yīng)請求的處理結(jié)果,下面列出了一些常見的狀態(tài)碼和相應(yīng)的原因短語:
圖3:響應(yīng)消息的一般格式
●200 0K;請求成功,所請求信息在響應(yīng)消息中返回。
●301 Moved Permanently:所請求的對象己永久性遷移;新的URL在本響應(yīng)消息的Location:頭部指出??蛻糗浖詣诱埱筮@個(gè)新的URL。
●400 Bad Request;表示服務(wù)器無法理解相應(yīng)請求的普通錯(cuò)誤的狀態(tài)碼
●404 Not Found:服務(wù)器上不存在所請求的文檔。
●HTTP Version Not Support:服務(wù)器不支持所請求的HTTP協(xié)議版本。
你想如何看到一個(gè)真實(shí)的H1TP應(yīng)答消息呢?這非常簡單??梢允褂胣c工具連接到你喜歡的服務(wù)器(nc/netcat是一個(gè)黑客很喜歡用的工具,可以方便在主機(jī)之間建立TCP連接),然后輸入一行請求消息,用來請求位于該服務(wù)器上的某個(gè)對象。例如,如果你可以輸入以下指令:
nc www.chinaitlab.com 80
GET /index.shtml HTTP/1.0
(在輸入第二行之后,敲兩次回車),這就打開了一個(gè)到主機(jī)www.chinaitlab.com的端口80的TCP連接,然后發(fā)送HTTP GET命令。你應(yīng)該能看到包含著YESKY主頁的基本HTML文件的應(yīng)苔消息。如果你想只看到HTTP消息行而不接收該對象本身,那么就把上面的GET換成HEAD。最后,看一下能得到什么樣的應(yīng)答消息。
在這里我們討論了大量能夠在HTTP請求和應(yīng)答消息中使用的頭部行。HTTP規(guī)范(尤其是HTTP/1.1)定義了更多可以由瀏覽器、Web服務(wù)器和網(wǎng)絡(luò)緩沖服務(wù)器插入的頭部行。
我們可以便用nc工具完全控制在請求消息中包含哪些頭部,那么瀏覽器如何決定該在請求消息個(gè)包含哪些頭部呢?Web服務(wù)器又是如何決定該在響應(yīng)消息中包含哪些頭部?瀏覽器是根據(jù)自己的用戶代理類型、所支持的HTTP版本(HTTP/1.0版本的瀏覽器自然不會產(chǎn)生HTTP/1.1版本的頭部)、用戶對瀏覽器的配置(如所偏愛的語言)等因素生成請求消息中的各個(gè)頭部的。web服務(wù)器有類似的情形:它們有不同的產(chǎn)品、版本和配置,所有這些因素都會影響在響應(yīng)消息中包含哪些頭部。
本文討論過的和即將討論的用于HTTP請求消息和響應(yīng)消息中的頭部僅僅是很小的一部分,HTTP規(guī)范中定義了更多可用的頭部,可以查閱相關(guān)的RFC文檔進(jìn)行更詳細(xì)的了解。
用戶—服務(wù)器交互
身份認(rèn)證和cookie
我們已經(jīng)知道HTTP服務(wù)器是無狀態(tài)的。這樣的處理可以簡化服務(wù)器程序的設(shè)計(jì),以便開發(fā)出更高性能的Web服務(wù)器軟件。然而,一個(gè)Web站點(diǎn)往往有標(biāo)識其用戶的需求,因?yàn)槠鋡eb服務(wù)器可能希望限制用戶的訪問,也可能想要根據(jù)用戶的身份來提供內(nèi)容。HTTP提供了兩種幫助服務(wù)器標(biāo)識用戶的機(jī)制:身份認(rèn)證和cookle。
身份認(rèn)證許多web站點(diǎn)要求用戶提供一個(gè)用戶名—口令對才能訪問存放在其服務(wù)器中的文檔。這種要求稱為身份認(rèn)證(authentication)。HTTP提供特殊的狀態(tài)碼和頭部來幫助Web站點(diǎn)執(zhí)行身份認(rèn)證。我們通過查看一個(gè)例子來領(lǐng)會這些特殊的狀態(tài)碼和頭部如何工作。假設(shè)有—個(gè)客戶在請求來自某個(gè)服務(wù)器的一個(gè)對象,而該服務(wù)器要求用戶授予權(quán)限。
客戶首先發(fā)送一個(gè)不合特殊頭部的普通請求消息。服務(wù)器以空的附屬體和一個(gè)“401Authorization Required”狀態(tài)碼作為響應(yīng)。服務(wù)器還在這個(gè)響應(yīng)消息中包含“個(gè)WWW-Authenticate:頭部,說明具體如何執(zhí)行身份認(rèn)證。這個(gè)頭部的典型值是指出用戶需要提供一個(gè)用戶名—口令對。
客戶收到這個(gè)響應(yīng)消息后提示用戶輸入用戶名和口令,然后重新發(fā)送請求消息。這一回客戶在請求消息中包含了一個(gè)Authorization:頭部,其中包含有用戶輸入的用戶名和口令。
取得第一個(gè)對象后,客戶在同為請求該服務(wù)器上對象的后續(xù)請求中繼續(xù)發(fā)送這個(gè)用戶名—口令對。這個(gè)做法一般將持續(xù)到用戶關(guān)閉瀏覽器為止。在瀏覽器未被關(guān)閉之前,這個(gè)用戶名—口令對是高速緩存著的,因此瀏覽器不會每請求一個(gè)對象就提示用戶輸入一次用戶名和口令。通過上述方式,要求用戶授權(quán)的Web站點(diǎn)就能標(biāo)識出每個(gè)請求的用戶了。
我們需要知道,HTTP執(zhí)行的是一種相當(dāng)脆弱的身份認(rèn)證方式,不難攻破?,F(xiàn)代有很多更為安全的認(rèn)證方式,我們會在以后介紹。
cookie是一種可讓W(xué)eb站點(diǎn)用來跟蹤用戶的候選機(jī)制,定義在RFC 2109中。有些Web站點(diǎn)使用cookie,其他Web站點(diǎn)則不用。下面查看一個(gè)例子。假設(shè)一個(gè)客戶首次聯(lián)系一個(gè)使用cookie的web站點(diǎn)。服務(wù)器會在其響應(yīng)中包含一個(gè)Set—Cookie:頭部。該頭部的值可以是一個(gè)由Web服務(wù)器產(chǎn)生的客戶標(biāo)識數(shù).例如:
Set-Cookie:1678453
客戶收到這個(gè)響應(yīng)消息,看到其中的Set-Cookie:頭部和標(biāo)識數(shù)后,會在存放在客戶主機(jī)中的某個(gè)特殊的cookie文件中添加一行。這一行一般包含服務(wù)器主機(jī)的主機(jī)名和這個(gè)與用戶關(guān)聯(lián)的標(biāo)識數(shù)。在一段時(shí)間(如一個(gè)星期)之后請求同一個(gè)服務(wù)器時(shí),由同一個(gè)用戶啟動的新客戶會在請求消息中包含一個(gè)cookie頭部,其值為早先由該服務(wù)器產(chǎn)生的標(biāo)識數(shù),例如:Cookie:1678453
在這種方式中,服務(wù)器并不知道提出請求的用戶的用戶名,但是它確實(shí)知道該用戶與一個(gè)星期前提出請求的用戶是同一個(gè)。
Web服務(wù)器有多個(gè)使用coohe的目的:
●如果服務(wù)器要求身份認(rèn)證,但又不想在同一用戶每次訪問本W(wǎng)eb站點(diǎn)時(shí)都麻煩他輸入用戶名和口令,那么可以設(shè)置一個(gè)cookie。
●如果服務(wù)器想要記住用戶的偏好,以便在他們后續(xù)訪問期間有目的地提供廣告,那么可以設(shè)置一個(gè)cookie。
●如果web站點(diǎn)提供購物服務(wù),那么服務(wù)器可以使用cookie跟蹤用戶購買的物品,就是建立一個(gè)虛擬的購物車。
需指出的是,cookie不適用于會從不同主機(jī)訪問同一web站點(diǎn)的游動用戶。這種情況下,該web站點(diǎn)會把同一個(gè)用戶在不同主機(jī)上的使用看成是由新的用戶執(zhí)行的。
帶條件的GET
Web高速緩存技術(shù)通過就近存取先前取得的對象來降低對象檢索延遲,減少因特網(wǎng)上的web流量。Web的高速緩存既可以駐留在客戶主機(jī)中,也可以駐留在中間網(wǎng)絡(luò)高速緩存服務(wù)器主機(jī)中。我們將在稍后討論網(wǎng)絡(luò)高速緩存,這里只關(guān)注客戶的高速緩存。
Web高速緩存在降低用戶可感知的響應(yīng)時(shí)間的同時(shí),卻引入了一個(gè)新的問題——高速緩存中存放的對象的拷貝可能是過期的。換句話說,存放在web服務(wù)器中的對象可能己在客戶高速緩存下它的一個(gè)拷貝之后被修改了。幸運(yùn)的是,HTTP提供一個(gè)專門的機(jī)制,使得在允許客戶進(jìn)行高速緩存的同時(shí),仍確保傳遞給瀏覽器的所有對象都是最新的。這個(gè)機(jī)制稱為帶條件的0ET(conditional GET)。滿足條件(1)使用GET方法和(2)包含If-Modified-S1nce:頭部的HTTP請求消息就是所謂的帶條件的Get消息。
我們通過查看一個(gè)例子來說明帶條件的GET如何工作,向服務(wù)器請求一個(gè)尚未高速緩存的對象:
GET /fruit/kiwi.gif HTTP/1.0
User—agent: Mozilla/4.0
接著,web服務(wù)器把帶這個(gè)對象的一個(gè)響應(yīng)消息發(fā)送給客戶:
HTTP/1.0 200 OK
Date: Thu, 13 Oct 2005 05:33:47 GMT
Server: Apache/2.0.54 (Unix)
Last-Modified:Thu, 13 Oct 2005 02:32:47 GMT
Content-Type:image/gif
(數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù)……)
客戶把這個(gè)對象顯示給用戶,同時(shí)把它保存在自己的本地高速緩存中客戶還隨該對象本身高速緩存最后修改日期與時(shí)間。一個(gè)星期之后,同一個(gè)用戶請求同一個(gè)對象,而該對象仍然存放在高速緩存中。既然web服務(wù)器中的該對象有可能已在最近一個(gè)星期被修改過,于是瀏覽器發(fā)出一個(gè)帶條件的GET消息,執(zhí)行判定高速緩存的對象拷貝是否為最新的檢查;
GET /fruit/kiwi.gif HTTP/1.0
User—agent: Mozilla/4.0
If—Modlfied—Since:Thu, 13 Oct 2005 02:32:47 GMT
其中,If—Modlfied—Since:頭部的值就等于一個(gè)星期前由服務(wù)器發(fā)送的Last-Modified:頭部的值。這個(gè)帶條件的GET消息告知服務(wù)器,只有在該對象自所指定的時(shí)間以來被修改了的前提下才發(fā)送它。假設(shè)該對象在這段時(shí)間內(nèi)未曾被修改過,那么服務(wù)器將發(fā)送一個(gè)附屬體為空的響應(yīng)消息給客戶;
HTTP/1.0 304 Not Modified
Date: Thu, 20 Oct 2005 05:33:47 GMT
Server: Apache/2.0.54 (Unix)
我們看到,web服務(wù)器仍然發(fā)送——個(gè)響應(yīng)消息作為帶條件的GET消息的響應(yīng),不過其中不包含所請求的對象。包含該對象只會浪費(fèi)帶寬,并延長用戶可感知的響應(yīng)時(shí)間,特別是在該對象很大的時(shí)候。注意,這個(gè)響應(yīng)消息的狀態(tài)為“304 Not Modified”,它告知客戶可以放心使用所請求對象的高速緩存版本。
用Socket類實(shí)現(xiàn)HTTP協(xié)議客戶端應(yīng)用
Http客戶端程序已集成在Java語言中,可以通過URLConnection類調(diào)用。遺憾的
是,由于SUN沒有公布Http客戶程序的源碼,它實(shí)現(xiàn)的細(xì)節(jié)仍是一個(gè)謎。本文根據(jù)HTTP
協(xié)議規(guī)范,用Java.net.Socket類實(shí)現(xiàn)一個(gè)HTTP協(xié)議客戶端程序。
1.Socket類:
了解TCP/IP協(xié)議集通信的讀者知道,協(xié)議間的通信是通過Socket完成的。在
Java.net包中,Socket類就是對Socket的具體實(shí)現(xiàn)。它通過連接到主機(jī)后,返回一個(gè)
I/O流,實(shí)現(xiàn)協(xié)議間的信息交換。
2 . HTTP協(xié)議
HTTP協(xié)議同其它TCP/IP協(xié)議集中的協(xié)議一樣,是遵循客戶/服務(wù)器模型工作的???div style="height:15px;">
戶端發(fā)往服務(wù)端的信息格式如下:
------------------------------
請求方法 URL HTTP協(xié)議的版本號
提交的元信息
**空行**
實(shí)體
------------------------------
請求方法是對這次連接工作的說明,目前HTTP協(xié)議已經(jīng)發(fā)展到1.1版,它包括GET、
HEAD、POST、DELETE、OPTIONS、TRACE、PUT七種。元信息是關(guān)于當(dāng)前請求的信息。通
過分析元信息,可以檢查實(shí)體數(shù)據(jù)是否完整,接收過程是否出錯(cuò),類型是否匹配等。元
信息的引入使HTTP協(xié)議通信更加穩(wěn)妥可靠。實(shí)體是請求的具體內(nèi)容。
將上述報(bào)文發(fā)往Web服務(wù)器,如果成功,應(yīng)答格式如下:
--------------------------------
HTTP協(xié)議的版本號 應(yīng)答狀態(tài)碼 應(yīng)答狀態(tài)碼說明
接收的元信息
**空行**
實(shí)體
--------------------------------
以上報(bào)文發(fā)向客戶端,并且接收成功,彼此間關(guān)閉連接,完成一次握手。
下面用最常用的GET方法,來說明具體的報(bào)文應(yīng)用
----------------------------------
GEThttp://www.youhost.com HTTP/1.0
accept: www/source; text/html; image/gif; image/jpeg; */*
User_Agent: myAgent
**空行**
-----------------------------------
這個(gè)報(bào)文是向www.youhost.com主機(jī)請求一個(gè)缺省HTML文檔??蛻舳薍TTP協(xié)議版本
號是1.0版,元信息包括可接收的文件格式,用戶代理,每一段之間用回車換行符分
隔,最后以一個(gè)空行結(jié)束。發(fā)向服務(wù)器后,如果執(zhí)行過程正常,服務(wù)器返回以下代碼:
------------------------------------
HTTP/1.1 200 OK
Date: Tue, 14 Sep 1999 02:19:57 GMT
Server: Apache/1.2.6
Connection: close
Content-Type: text/html
**空行**
......
------------------------------------
HTTP/1.1表示這個(gè)HTTP服務(wù)器是1.1版,200是服務(wù)器對客戶請求的應(yīng)答狀態(tài)碼,OK
是對應(yīng)答狀態(tài)碼的解釋,之后是這個(gè)文檔的元信息和文檔正文。(相關(guān)應(yīng)答狀態(tài)碼和元
信息的解釋請參閱Inetrnet標(biāo)準(zhǔn)草案:RFC2616)。
3. HTTP客戶端程序:
import java.net.*;
import java.io.*;
import java.util.Properties;
import java.util.Enumeration;
public class Http {
protected Socket client;
protected BufferedOutputStream sender;
protected BufferedInputStream receiver;
protected ByteArrayInputStream byteStream;
protected URL target;
private int responseCode=-1;
private String responseMessage="";
private String serverVersion="";
private Properties header = new Properties();
public Http() { }
public Http(String url) {
GET(url) ;
}
/* GET方法根據(jù)URL,會請求文件、數(shù)據(jù)庫查詢結(jié)果、程序運(yùn)行結(jié)果等多種內(nèi)容 */
public void GET(String url) {
try {
checkHTTP(url);
openServer(target.getHost(),target.getPort() );
String cmd = "GET "+ getURLFormat(target) +" HTTP/1.0\r\n"
+ getBaseHeads()+"\r\n";
sendMessage(cmd);
receiveMessage();
}catch(ProtocolException p) {
p.printStackTrace();
return;
}catch(UnknownHostException e) {
e.printStackTrace();
return;
}catch(IOException i)
i.printStackTrace();
return;
}
}
/*
* HEAD方法只請求URL的元信息,不包括URL本身。若懷疑本機(jī)和服務(wù)器上的
* 文件相同,用這個(gè)方法檢查最快捷有效。
*/
public void HEAD(String url) {
try {
checkHTTP(url);
openServer(target.getHost(),target.getPort() );
String cmd = "HEAD "+getURLFormat(target)+" HTTP/1.0\r\n"
+getBaseHeads()+"\r\n";
sendMessage(cmd);
receiveMessage();
}catch(ProtocolException p) {
p.printStackTrace();
return;
}catch(UnknownHostException e) {
e.printStackTrace();
return;
}catch(IOException i)
i.printStackTrace();
return;
}
}
/*
* POST方法是向服務(wù)器傳送數(shù)據(jù),以便服務(wù)器做出相應(yīng)的處理。例如網(wǎng)頁上常用的
* 提交表格。
*/
public void POST(String url,String content) {
try {
checkHTTP(url);
openServer(target.getHost(),target.getPort() );
String cmd = "POST "+ getURLFormat(target) +"
HTTP/1.0\r\n"+getBaseHeads();
cmd += "Content-type: application/x-www-form-urlencoded\r\n";
cmd += "Content-length: " + content.length() + "\r\n\r\n";
cmd += content+"\r\n";
sendMessage(cmd);
receiveMessage();
}catch(ProtocolException p) {
p.printStackTrace();
return;
}catch(UnknownHostException e) {
e.printStackTrace();
return;
}catch(IOException i)
i.printStackTrace();
return;
}
}
protected void checkHTTP(String url) throws ProtocolException {
try {
URL target = new URL(url);
if(target==null || !target.getProtocol().toUpperCase().equals("HTTP") )
throw new ProtocolException("這不是HTTP協(xié)議");
this.target = target;
}catch(MalformedURLException m) {
throw new ProtocolException("協(xié)議格式錯(cuò)誤");
}
}
/*
* 與Web服務(wù)器連接。若找不到Web服務(wù)器,InetAddress會引發(fā)UnknownHostException
* 異常。若Socket連接失敗,會引發(fā)IOException異常。
*/
protected void openServer(String host,int port) throws
UnknownHostException,IOException {
header.clear();
responseMessage=""; responseCode=-1;
try {
if(client!=null) closeServer();
if(byteStream != null) {
byteStream.close(); byteStream=null;
}
InetAddress address = InetAddress.getByName(host);
client = new Socket(address,port==-1?80:port);
sender = new BufferedOutputStream(client.getOutputStream());
receiver = new BufferedInputStream(client.getInputStream());
}catch(UnknownHostException u) {
throw u;
}catch(IOException i) {
throw i;
}
}
/* 關(guān)閉與Web服務(wù)器的連接 */
protected void closeServer() throws IOException {
if(client==null) return;
try {
client.close(); sender.close(); receiver.close();
}catch(IOException i) {
throw i;
}
client=null; sender=null; receiver=null;
}
protected String getURLFormat(URL target) {
String spec = "http://"+target.getHost();
if(target.getPort()!=-1)
spec+=":"+target.getPort();
return spec+=target.getFile();
}
/* 向Web服務(wù)器傳送數(shù)據(jù) */
protected void sendMessage(String data) throws IOException{
sender.write(data.getBytes(),0,data.length());
sender.flush();
}
/* 接收來自Web服務(wù)器的數(shù)據(jù) */
protected void receiveMessage() throws IOException{
byte data[] = new byte[1024];
int count=0;
int word=-1;
// 解析第一行
while( (word=receiver.read())!=-1 ) {
if(word==‘\r‘||word==‘\n‘) {
word=receiver.read();
if(word==‘\n‘) word=receiver.read();
break;
}
if(count == data.length) data = addCapacity(data);
data[count++]=(byte)word;
}
String message = new String(data,0,count);
int mark = message.indexOf(32);
serverVersion = message.substring(0,mark);
while( mark responseCode = Integer.parseInt(message.substring(mark+1,mark+=4));
responseMessage = message.substring(mark,message.length()).trim();
// 應(yīng)答狀態(tài)碼和處理請讀者添加
switch(responseCode) {
case 400:
throw new IOException("錯(cuò)誤請求");
case 404:
throw new FileNotFoundException( getURLFormat(target) );
case 503:
throw new IOException("服務(wù)器不可用" );
}
if(word==-1) throw new ProtocolException("信息接收異常終止");
int symbol=-1;
count=0;
// 解析元信息
while( word!=‘\r‘ && word!=‘\n‘ && word>-1) {
if(word==‘\t‘) word=32;
if(count==data.length) data = addCapacity(data);
data[count++] = (byte)word;
parseLine: {
while( (symbol=receiver.read()) >-1 ) {
switch(symbol) {
case ‘\t‘:
symbol=32; break;
case ‘\r‘:
case ‘\n‘:
word = receiver.read();
if( symbol==‘\r‘ && word==‘\n‘) {
word=receiver.read();
if(word==‘\r‘) word=receiver.read();
}
if( word==‘\r‘ || word==‘\n‘ || word>32) break parseLine;
symbol=32; break;
}
if(count==data.length) data = addCapacity(data);
data[count++] = (byte)symbol;
}
word=-1;
}
message = new String(data,0,count);
mark = message.indexOf(‘:‘);
String key = null;
if(mark>0) key = message.substring(0,mark);
mark++;
while( mark String value = message.substring(mark,message.length() );
header.put(key,value);
count=0;
}
// 獲得正文數(shù)據(jù)
while( (word=receiver.read())!=-1) {
if(count == data.length) data = addCapacity(data);
data[count++] = (byte)word;
}
if(count>0) byteStream = new ByteArrayInputStream(data,0,count);
data=null;
closeServer();
}
public String getResponseMessage() {
return responseMessage;
}
public int getResponseCode() {
return responseCode;
}
public String getServerVersion() {
return serverVersion;
}
public InputStream getInputStream() {
return byteStream;
}
public synchronized String getHeaderKey(int i) {
if(i>=header.size()) return null;
Enumeration enum = header.propertyNames();
String key = null;
for(int j=0; j<=i; j++)
key = (String)enum.nextElement();
return key;
}
public synchronized String getHeaderValue(int i) {
if(i>=header.size()) return null;
return header.getProperty(getHeaderKey(i));
}
public synchronized String getHeaderValue(String key) {
return header.getProperty(key);
}
protected String getBaseHeads() {
String inf = "User-Agent: myselfHttp/1.0\r\n"+
"Accept: www/source; text/html; image/gif; */*\r\n";
return inf;
}
private byte[] addCapacity(byte rece[]){
byte temp[] = new byte[rece.length+1024];
System.arraycopy(rece,0,temp,0,rece.length);
return temp;
}
}
注: 程序中只實(shí)現(xiàn)GET、HEAD、POST三種方法。其他幾種因不常使用,暫且忽略。
HTTP:超文本傳輸協(xié)議
HTTP:Hypertext Transfer Protocol
超文本傳輸協(xié)議(HTTP)是應(yīng)用層協(xié)議,由于其簡捷、快速的方式,適用于分布式和合作式超媒體信息系統(tǒng)。自 1990 年起, HTTP 就已經(jīng)被應(yīng)用于 WWW 全球信息服務(wù)系統(tǒng)。
HTTP 允許使用自由答復(fù)的方法表明請求目的,它建立在統(tǒng)一資源識別器(URI)提供的參考原則下,作為一個(gè)地址(URL)或名字(URN),用以標(biāo)志采用哪種方法,它用類似于網(wǎng)絡(luò)郵件和多用途網(wǎng)際郵件擴(kuò)充協(xié)議(MIME)的格式傳遞消息。
HTTP 也可用作普通協(xié)議,實(shí)現(xiàn)用戶代理與連接其它 Internet 服務(wù)(如 SMTP 、 NNTP 、 FTP 、 GOPHER 及 WAIS )的代理服務(wù)器或網(wǎng)關(guān)之間的通信,允許基本的超媒體訪問各種應(yīng)用提供的資源,同時(shí)簡化了用戶代理系統(tǒng)的實(shí)施。
HTTP 是一種請求 / 響應(yīng)式的協(xié)議。一個(gè)客戶機(jī)與服務(wù)器建立連接后,發(fā)送一個(gè)請求給服務(wù)器,請求的格式是:統(tǒng)一資源標(biāo)識符(URI)、協(xié)議版本號,后面是類似 MIME 的信息,包括請求修飾符、客戶機(jī)信息和可能的內(nèi)容。服務(wù)器接到請求后,給予相應(yīng)的響應(yīng)信息,其格式是:一個(gè)狀態(tài)行包括信息的協(xié)議版本號、一個(gè)成功或錯(cuò)誤的代碼,后面也是類似 MIME 的信息,包括服務(wù)器信息、實(shí)體信息和可能的內(nèi)容。
HTTP 的第一版本 HTTP/0.9 是一種簡單的用于網(wǎng)絡(luò)間原始數(shù)據(jù)傳輸?shù)膮f(xié)議。而由 RFC 1945 定義的 HTTP/1.0 ,在原 HTTP/0.9 的基礎(chǔ)上,有了進(jìn)一步的改進(jìn),允許消息以類 MIME 信息格式存在,包括請求 / 響應(yīng)范式中的已傳輸數(shù)據(jù)和修飾符等方面的信息。但是, HTTP/1.0 沒有充分考慮到分層代理服務(wù)器、高速緩沖存儲器、持久連接需求或虛擬主機(jī)等方面的效能。相比之下, HTTP/1.1 要求更加嚴(yán)格以確保服務(wù)的可靠性。關(guān)于安全增強(qiáng)版的 HTTP (即S-HTTP),將在相關(guān)文件中再作介紹。
協(xié)議結(jié)構(gòu)
HTTP報(bào)文由從客戶機(jī)到服務(wù)器的請求和從服務(wù)器到客戶機(jī)的響應(yīng)構(gòu)成。 請求報(bào)文格式如下:
請求行通用信息頭請求頭實(shí)體頭報(bào)文主體
請求行以方法字段開始,后面分別是 URL 字段和 HTTP 協(xié)議版本字段,并以 CRLF 結(jié)尾。SP 是分隔符。除了在最后的 CRLF 序列中 CF 和 LF 是必需的之外,其他都可以不要。有關(guān)通用信息頭,請求頭和實(shí)體頭方面的具體內(nèi)容可以參照相關(guān)文件。
應(yīng)報(bào)文格式如下:
狀態(tài)行通用信息頭響應(yīng)頭實(shí)體頭報(bào)文主體
狀態(tài)碼元由3位數(shù)字組成,表示請求是否被理解或被滿足。原因分析是對原文的狀態(tài)碼作簡短的描述,狀態(tài)碼用來支持自動操作,而原因分析用來供用戶使用??蛻魴C(jī)無需用來檢查或顯示語法。有關(guān)通用信息頭,響應(yīng)頭和實(shí)體頭方面的具體內(nèi)容可以參照相關(guān)文件。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
持久連接與非持久連接
HTTP1.0與HTTP1.1的區(qū)別
HTTP頭信息解讀
HTTP協(xié)議及其工作原理介紹
【Linux】HTTP響應(yīng)報(bào)文與工作原理詳解
HTTP請求方式中8種請求方法(簡單介紹)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服