HTTP自1990 年以來就被全球信息網(wǎng)采用為基礎通訊協(xié)議,它是一種應用層的通訊協(xié)議,特性是輕便、快速,特別適合如Web 這種分布式、合作式的超媒體信息系統(tǒng)。HTTP 雖早自1990 年起就已被普遍使用,但過去許多年并無統(tǒng)一規(guī)范,此項不明確的規(guī)范后來通稱為HTTP/0.9。直到1996 年6 月一份僅供參考的文件才由Internet Society 的HTTP Working Group 出版,稱為HTTP/1.0。
HTTP/1.0 傳輸格式就像大部分的網(wǎng)絡通訊協(xié)議,HTTP 使用C/S模式。但是,HTTP/1.0沒有充分考慮到分層代理,高速緩存的作用以及對穩(wěn)定連接和虛擬主機的需求。并且隨著不完善的進程應用的激增,HTTP/1.0迫切需要一個新的版本,以便使兩個通信應用程序能夠確定彼此的真實性能。
這里規(guī)定的協(xié)議叫做“HTTP/1.1”,這個協(xié)議與HTTP/1.0相比,要求更為嚴格,以確保各項功能得到可靠實現(xiàn)。
在我們?nèi)粘I钪凶畛R姷膽铆h(huán)境就是上網(wǎng)瀏覽網(wǎng)頁,很多上班族到辦公室的第一件事就是打開電腦,而開機后的第一件事就是打開IE、Firefox、Myie、GreenBrowser、Opera等瀏覽器時,做的第一件事就是瀏覽一下例如www.sina.com.cn, www.163.com的新聞,而這種簡單的應用操作,完成的交互過程就是一個典型的HTTP協(xié)議的應用過程。
基于HTTP協(xié)議的客戶/服務器模式的信息交換過程,它分四個過程:建立連接、發(fā)送請求信息、發(fā)送響應信息、關閉連接。如圖1
HTTP_圖1
顯而易見有如下4個交互的過程:
連接的建立是通過申請?zhí)捉幼?Socket)實現(xiàn)的??蛻舸蜷_一個套接字并把它約束在一個端口上,如果成功,就相當于建立了一個虛擬文件。以后就可以在該虛擬文件上寫數(shù)據(jù)并通過網(wǎng)絡向外傳送。通俗地說就是TCP的三次握手。
首先,這個消息是用普通的ASCII文本書寫的。這個消息共有多行(每行以一個回車符和一個換行符結(jié)束),最后一行后面還有額外的一個回車符和換行符。當然,一個請求消息也可以僅僅只有一行。請求的報文中包含了各種信息,包括客戶端想要訪問的URL,HTTP的版本,支持的瀏覽的字體等內(nèi)容。詳細分析見2.2.1請求報文字段。
服務器在處理完客戶的請求之后,要向客戶機發(fā)送響應消息。
這個響應消息分為3部分:1個起始的狀態(tài)行(status line),6個頭部行(不固定)、1個包含所請求對象本身的附屬體。狀態(tài)行有3個字段:協(xié)議版本字段、狀態(tài)碼字段、原因短語字段。詳細分析見2.2.2應答報文字段。
客戶和服務器雙方都可以通過關閉套接字來結(jié)束TCP/IP對話。通俗地說就是TCP的4次握手斷開。常見的應用環(huán)境就是這樣,實際生活中可能就是多了一個NAT轉(zhuǎn)換,其實過程都是一樣的。
在很多網(wǎng)絡安全產(chǎn)品中,提供了HTTP過濾的功能,要求客戶在IE瀏覽器上做一個【Internet選項】->【連接】->【局域網(wǎng)設置】的更改,配置代理的ip和端口。如下圖2:
HTTP_圖2
點擊【局域網(wǎng)設置】后輸入ip和端口,并鉤選“為LAN使用代理服務器”如下圖3:
HTTP_圖3
客戶端和代理主機間用交換機相連,下面的拓撲中為了看得更加清晰并沒有畫出交換機。
下面是一個簡單的拓撲圖4:
HTTP_圖4
詳細的交互過程分析參見:3.3
HTTP報文格式并不復雜,但是各個字段類型數(shù)量龐大,這里只對常見的字段進行分析。
對于下面字段說明中出現(xiàn)的一些常見字符作一下說明:
“文字”
文字原文使用引號。除特殊情況,原文對外界不敏感。
規(guī)則1 | 規(guī)則2
由豎線("|")分開的元素是可選的,例如,"yes | no"表示yes或no都是可接受的。
(規(guī)則1 規(guī)則2)
圍在括號里的多個元素視作一個元素。這樣“(elem (foo | bar) elem)”允許標記序列“elem foo elem”和elem bar elem”。
*規(guī)則
前面的字符"*"表示重復。完整的形式是"*元素",表示元素至少出現(xiàn)次,至多出現(xiàn)次。默認值是0和無窮大,所以"*(元素)"允許任何數(shù)值,包括零;"1*元素"至少需要一次;"1*2element"允許一次或兩次。
[規(guī)則]
方括號里是任選元素;"[foo bar]"相當于"*1(foo bar)"。
對于HTTP的報文格式分析,就是兩種格式,因為基于C/S的訪問應答模式,所以一個是請求的報文格式,而另一個是應答的報文格式。
先看一下請求報文格式的作圖,如圖5:
HTTP_圖5
文本分析一下請求報文的內(nèi)容:
請求 =請求行 Request Line
*((常規(guī)報頭 General Header
|請求報頭 Request Header
|實體報頭)CRLF) Entity Header
CRLF
[消息正文] Message Body
說明:
HTTP/1.1將CR LF的順序定義為任何協(xié)議元素的行尾標志,CR= LF= 。
先看一下應答報文格式的作圖,如圖6:
HTTP_圖6
文本分析一下應答報文的內(nèi)容:
應答 ?。綘顟B(tài)行 Status Line
*((常規(guī)報頭(general-header) General Header
|應答報頭(response-header) Response Header
|實體報頭(entity-header)CRLF) Entity Header
CRLF
[應答正文] Message Body
根據(jù)上面提到的請求報文和應答報文的格式,對每個字段進行描述。
如圖7:
HTTP_圖7
請求消息的第一行稱為請求行(request line),請求行有3個字段:
方法字段(Request Method)圖7中為:GET;
URL字段(Request URL)圖7中為:/forumdisplay.php?fid=6,這個字段可以是一個“/;
HTTP協(xié)議不對URL的長度作事先的限制.服務器必須能夠處理它們服務的任何資源的URL,并且應該能夠處理無限長度的URL,如果它們提供可以產(chǎn)生這種URL的基于GET的形式。
HTTP版本字段(Request Version)。圖7中為:HTTP/1.1。
看一下RFC2616中的截圖8:
HTTP_圖8
常見的方法字段說明:
GET: 請求指定的頁面信息,并返回實體主體。
HEAD: 只請求頁面的首部。
POST:請求服務器接受所指定的文檔作為對所標識的URL的新的從屬實體。
PUT: 從客戶端向服務器傳送的數(shù)據(jù)取代指定的文檔的內(nèi)容。
DELETE: 請求服務器刪除指定的頁面。
OPTIONS: 允許客戶端查看服務器的性能。
需要特別說明的是方法字段有若干個值可供選擇,最常見的包括GET、POST和HEAD。
而且HEAD字段并不好抓包顯示,但是這個字段的作用卻需要注意,HTML中的head標記是網(wǎng)頁標記中一個非常重要的符號,head標記中包含的內(nèi)容基本上描述了所屬頁面的基本屬性,包括標題、字符集、站點信息、網(wǎng)站作者信息、站點描述、站點關鍵詞、搜索引擎蜘蛛引導、刷新及跳轉(zhuǎn)、樣式表鏈入以及其它一些有用的附加功能。例如:
簡體中文:“ ”
繁體中文:“ ”
英 語:“”
禁止瀏覽器從本地機的緩存中調(diào)閱頁面內(nèi)容。
例子:“ ”
/P>
后續(xù)各行都稱為請求頭部行(header),即請求報頭。其中RFC2616中定義常見的有:
HTTP_圖9
常見的頭部說明:
Accept:可以接受的媒體;
Accept-Charset:可以接受的字符集;
Accept-Encoding:可以接受的編碼方案;
Accept-Language:能夠接受的語言;
Host:主機和端口號;
Referer:指明被連接的目標URL。
同時RFC2616注明可以根據(jù)需要擴展自定義的頭部行:
原文:Request-header field names can be extended reliably only in combination with a change in the protocol version. However, new or experimental header fields MAY be given the semantics of request-header fields if all parties in the communication recognize them to be request-header fields. Unrecognized header fields are treated as entity-header fields.
翻譯:隨著協(xié)議版本的變化,請求報頭域的名字可以可靠的擴展。然而新的或擴展的報頭域可以給出請求報頭域的語法,其前提是通信中所有部分承認它們是請求報頭域。不被承認的報頭域被當作實體報頭域。
如圖10:
HTTP_圖10
應答信息的第一行是狀態(tài)行,由協(xié)議版本以及數(shù)字狀態(tài)碼和相關的文本說明組成,各部分間用空格符隔開,除了最后的回車或換行外,中間不允許有回車換行,注意HTTP/1.1后面沒有rn。
狀態(tài)行中的狀態(tài)碼是試圖理解和滿足請求的三位數(shù)字的整數(shù)碼,狀態(tài)碼用于自動控制而注解短語是面向用戶的,客戶機不需要檢查和顯示注解短語。
圖10中返回的協(xié)議版本為HTTP/1.1,注意,請求的HTTP版本可以和返回的HTTP不一致。返回的狀態(tài)碼為200 OK。
狀態(tài)碼的第一位數(shù)字定義應答類型,后兩位數(shù)字沒有任何類型任務,第一位數(shù)字有五種值:
-1xx: 報告的 - 接收到請求,繼續(xù)進程.
-2xx 成功 - 操作成功的收到.
-3xx 重發(fā) - 為了完成請求,必須采取進一步措施.
-4xx 客戶端出錯 - 請求包括錯的順序或不能完成.
-5xx 服務器出錯 - 服務器無法完成顯然有效的請求.
HTTP協(xié)議狀態(tài)碼的具體含義 :
"100" : Continue 繼續(xù);
"101" : witching Protocols 轉(zhuǎn)換協(xié)議;
"200" : OK 成功;
"201" : Created 創(chuàng)建;
"202" : Accepted 接受;
"203" : Non-Authoritative Information 非權(quán)威信息;
"204" : No Content 無內(nèi)容;
"205" : Reset Content 重置內(nèi)容;
"206" : Partial Content 局部內(nèi)容;
"300" : Multiple Choices 多樣選擇;
"301" : Moved Permanently 永久移動;
"302" : Found 創(chuàng)立;
"303" : See Other 觀察別的部分;
"304" : Not Modified 只讀;
"305" : Use Proxy 用戶代理;
"307" : Temporary Redirect 臨時重發(fā);
"400" : Bad Request 壞請求;
"401" : Unauthorized 未授權(quán)的;
"402" : Payment Required 必要的支付;
"403" : Forbidden 禁用;
"404" : Not Found 沒找到;
"405" : Method Not Allowed 不允許的方式;
"406" : Not Acceptable 不接受;
"407" : Proxy Authentication Required 需要代理驗證;
"408" : Request Time-out 請求超時;
"409" : Conflict 沖突;
"410" : Gone 以往的;
"411" : Length Required 需要的長度;
"412" : Precondition Failed 預處理失??;
"413" : Request Entity Too Large 請求實體太大;
"414" : Request-URL Too Large 請求URL太大;
"415" : Unsupported Media Type 不支持的媒體類型;
"416" : Requested range not satisfiable 請求的范圍不足;
"417" : Expectation Failed 期望失敗;
"500" : Internal Server Error 服務器內(nèi)部出錯;
"501" : Not Implemented 不能實現(xiàn);
"502" : Bad Gateway 壞網(wǎng)關;
"503" : Service Unavailable 服務器不能實現(xiàn);
"504" : Gateway Time-out 網(wǎng)關超時;
"505" : HTTP Version not supported HTTP版本不支持。
應答頭允許服務器傳送應答的附加信息,這些信息不能放在狀態(tài)行里.這些報頭域給出有關服務器的信息以及請求URL指定的資源的下一步的通路。
RFC2616中定義的應答頭部行,圖11:
HTTP_圖11
常見的應答頭部說明:
Accept-Ranges:給出客戶請求的范圍;
Age:給出文檔的使用期限;
Location:重新定向后的位置;
Server:給出服務器和版本號。
隨著協(xié)議版本的變化,應答報頭可以可靠的擴展。而且,如果通信的所有組成部分都把它當作應答報頭域,新的或試驗性的應答報頭域可以被給定應答報頭域的含義,未被承認的報頭域被當作實體報頭域。
這個字段可能經(jīng)常被誤以為是頭部字段中的內(nèi)容,在未經(jīng)特別規(guī)定的情況下,請求與應答的報文也可以傳送實體。實體包括實體報頭與實體正文,而有些應答只包括實體報頭。
實體報文域定義了關于實體正文的維護信息(參數(shù)),或在無正文情況下定義了請求的資源。其中一些參數(shù)是可選的,一些則是由技術指標規(guī)定必須的。
參見RFC2612的圖12:
HTTP_圖12
可以從中看出實體字段主要規(guī)定的是內(nèi)容編碼(Content-Encoding)、內(nèi)容類型(Content-Type)、內(nèi)容語言(Content-Language)、內(nèi)容長度(Content-Length)、上次修改(Last-Modified)等信息。
經(jīng)由HTTP請求或應答發(fā)送的實體正文部分(如果存在的話)的格式與編碼方式應由實體報文域決定。
實體正文= *八位字節(jié)
實體正文只有當報文正文存在時才存在。實體正文是通過對報文正文按某種保證安全性且便于傳輸?shù)膫鬏斁幋a進行解碼得到的。對于報文中的實體正文而言,其數(shù)據(jù)類型由報頭中的"內(nèi)容類型"與"內(nèi)容編碼"域決定。也即定義了一個雙層有序的編碼模型:
實體正文=內(nèi)容編碼(內(nèi)容類型(數(shù)據(jù)))
"內(nèi)容類型"規(guī)定了基本數(shù)據(jù)的媒體類型。
"內(nèi)容編碼"則可用來指明對數(shù)據(jù)施加的任何附加的,通常以數(shù)據(jù)壓縮為目的的編碼方式,并將其作為所請求資源的一項屬性。沒有缺省的編碼方式。
任一包含了實體正文的HTTP/1.1報文都應包括"內(nèi)容類型"(Content-Type)報頭域,以定義正文的媒體類型。當且僅當"內(nèi)容類型"域未給出媒體類型時,接收者才可以通過查看資源的內(nèi)容,擴展名或URL來猜測其媒體類型。若媒體類型仍然未知,接收者應將其作為"應用/八位字節(jié)流"來處理。
報文的實體長度指的是在對報文進行傳輸編碼前報文正文的長度。圖10中標記的內(nèi)容長度。
在持續(xù)連接之前,為獲取每一URL都建立了獨立的TCP 連接,這就加重了HTTP服務器的負擔,易引起INTERNET阻塞。嵌入式圖片與其它相關數(shù)據(jù)通常使用戶在短時間內(nèi)對同一服務器提交多個請求。HTTP/1.1 與HTTP/1.0 版本的一個顯著區(qū)別在于持續(xù)連接是任何HTTP連接的缺省方式。也就是說,除非另有指定,客戶機總應當假定服務器會保持持續(xù)連接,即便在接到服務器的出錯應答時也應如此。
注意:在測試驗證過程中出現(xiàn)過一種特殊情況,在IE上設置代理上網(wǎng),在代理服務器上(如圖4)抓到的報文卻是HTTP/1.0的請求。改用Firefox瀏覽器設置代理上網(wǎng)卻不會出現(xiàn)這個情況。后來發(fā)現(xiàn)是IE自身設置的問題,在【internet選項】->【高級】->HTTP1.1設置中有一個【通過代理連接使用HTTP1.1】的鉤選項。
持續(xù)HTTP 連接有著諸多的優(yōu)點:
--- 通過建立與關閉較少的連接,不僅節(jié)省了路由器與主機(客戶機,服務器,代理服務器,網(wǎng)關,隧道或高速緩沖存儲機)的CPU時間,還節(jié)省了主機用于TCP協(xié)議控制塊的內(nèi)存。
--- HTTP請求與應答可以進入連接流水線。流水線方式使得客戶無須挨個等待應答即發(fā)起多個請求,從而更充分的利用了單個的TCP連接,減少了崩潰時間。
--- 在減少TCP連接中數(shù)據(jù)包個數(shù)的同時,使TCP有了充裕的時間來確定網(wǎng)絡的擁塞狀況,緩解了網(wǎng)絡擁塞。
--- 因為無須在創(chuàng)建TCP連接握手上耗費時間,而使連續(xù)請求造成的延遲現(xiàn)象得到改善。
--- 由于出錯不會導致TCP連接的關閉,HTTP可以更好的實現(xiàn)自我完善。使用較新版HTTP的用戶會樂于嘗試一些新功能,與舊版服務器通信時,則會在接到出錯報告后用舊模式重試。