http協(xié)議與http代理
TCP/IP(Transmission Control Protocol/InternetProtocol,傳輸控制協(xié)議/網(wǎng)際協(xié)議)是用于計(jì)算機(jī)通信的一個(gè)協(xié)議族。 TCP/IP協(xié)議族包括諸如Internet協(xié)議(IP)、地址解析協(xié)議(ARP)、互聯(lián)網(wǎng)控制信息協(xié)議(ICMP)、用戶數(shù)據(jù)報(bào)協(xié)議(UDP)、傳輸控制協(xié)議(TCP)、路由信息協(xié)議(RIP)、Telnet、簡(jiǎn)單郵件傳輸協(xié)議(SMTP)、域名系統(tǒng)(DNS)等協(xié)議。
1. 應(yīng)用層 應(yīng)用層包含一切與應(yīng)用相關(guān)的功能,我們經(jīng)常使用的HTTP、FTP,Telnet、SMTP等協(xié)議都在這一層實(shí)現(xiàn)。
2. 傳輸層 傳輸層負(fù)責(zé)提供可靠的傳輸服務(wù)。在該層中,典型的協(xié)議是TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)。其中,TCP提供可靠、有序的,面向連接的通信服務(wù);而UDP則提供無連接的、不可靠用戶數(shù)據(jù)報(bào)服務(wù)。
3. 網(wǎng)際層 網(wǎng)際層負(fù)責(zé)網(wǎng)絡(luò)間的尋址和數(shù)據(jù)傳輸,在該層中,典型的協(xié)議是IP(Internet Protocol)。
4. 網(wǎng)絡(luò)接口層 最下面一層是網(wǎng)絡(luò)接口層,負(fù)責(zé)數(shù)據(jù)的實(shí)際傳輸.網(wǎng)絡(luò)接口層在發(fā)送端將上層的IP數(shù)據(jù)報(bào)封裝成幀后發(fā)送到網(wǎng)絡(luò)上;數(shù)據(jù)幀通過網(wǎng)絡(luò)到達(dá)接收端時(shí),該結(jié)點(diǎn)的網(wǎng)絡(luò)接口層對(duì)數(shù)據(jù)幀拆封,并檢查幀中包含的MAC地址。如果該地址就是本機(jī)的MAC地址或者是廣播地址,則上傳到網(wǎng)絡(luò)層,否則丟棄該幀。
圖1 TCP/IP協(xié)議棧
協(xié)議概述
HTTP是一個(gè)客戶端終端(用戶)和服務(wù)器端(網(wǎng)站)請(qǐng)求和應(yīng)答的標(biāo)準(zhǔn)(TCP)。通過使用Web瀏覽器、網(wǎng)絡(luò)爬蟲或者其它的工具,客戶端發(fā)起一個(gè)HTTP請(qǐng)求到服務(wù)器上指定端口(默認(rèn)端口為80)。我們稱這個(gè)客戶端為用戶代理程序(user agent)。應(yīng)答的服務(wù)器上存儲(chǔ)著一些資源,比如HTML文件和圖像。我們稱這個(gè)應(yīng)答服務(wù)器為源服務(wù)器(origin server)。在用戶代理和源服務(wù)器中間可能存在多個(gè)中間層,比如代理,網(wǎng)關(guān),或者隧道(tunnel)。
盡管TCP/IP協(xié)議是互聯(lián)網(wǎng)上***的應(yīng)用,HTTP協(xié)議中,并沒有規(guī)定必須使用它或它支持的層。事實(shí)上,HTTP可以在任何互聯(lián)網(wǎng)協(xié)議上,或其他網(wǎng)絡(luò)上實(shí)現(xiàn)。HTTP假定其下層協(xié)議提供可靠的傳輸。因此,任何能夠提供這種保證的協(xié)議都可以被其使用。因此也就是其在TCP/IP協(xié)議族使用TCP作為其傳輸層。
通常,由HTTP客戶端發(fā)起一個(gè)請(qǐng)求,創(chuàng)建一個(gè)到服務(wù)器指定端口(默認(rèn)是80端口)的TCP連接。HTTP服務(wù)器則在那個(gè)端口監(jiān)聽客戶端的請(qǐng)求。一旦收到請(qǐng)求,服務(wù)器會(huì)向客戶端返回一個(gè)狀態(tài),比如"HTTP/1.1 200 OK",以及返回的內(nèi)容,如請(qǐng)求的文件、錯(cuò)誤消息、或者其它信息。
請(qǐng)求信息(Request Message)
發(fā)出的請(qǐng)求信息包括以下幾個(gè)
·1. 請(qǐng)求行
例如GET /images/logo.gif HTTP/1.1,表示從/images目錄下請(qǐng)求logo.gif這個(gè)文件。
2. 請(qǐng)求頭
例如Accept-Language: en
3. 空行
4. 其他消息體
請(qǐng)求行和標(biāo)題必須以作為結(jié)尾??招袃?nèi)必須只有而無其他空格。在HTTP/1.1協(xié)議中,所有的請(qǐng)求頭,除Host外,都是可選的。
請(qǐng)求方法
HTTP/1.1協(xié)議中共定義了八種方法(也叫“動(dòng)作”)來以不同方式操作指定的資源:
1. OPTIONS:這個(gè)方法可使服務(wù)器傳回該資源所支持的所有HTTP請(qǐng)求方法。用'*'來代替資源名稱,向Web服務(wù)器發(fā)送OPTIONS請(qǐng)求,可以測(cè)試服務(wù)器功能是否正常運(yùn)作。
2. HEAD:與GET方法一樣,都是向服務(wù)器發(fā)出指定資源的請(qǐng)求。只不過服務(wù)器將不傳回資源的本文部份。它的好處在于,使用這個(gè)方法可以在不必傳輸全部?jī)?nèi)容的情況下,就可以獲取其中“關(guān)于該資源的信息”(元信息或稱元數(shù)據(jù))。
3. GET:向指定的資源發(fā)出“顯示”請(qǐng)求。使用GET方法應(yīng)該只用在讀取數(shù)據(jù),而不應(yīng)當(dāng)被用于產(chǎn)生“副作用”的操作中,例如在Web Application中。其中一個(gè)原因是GET可能會(huì)被網(wǎng)絡(luò)蜘蛛等隨意訪問。參見安全方法
4. POST:向指定資源提交數(shù)據(jù),請(qǐng)求服務(wù)器進(jìn)行處理(例如提交表單或者上傳文件)。數(shù)據(jù)被包含在請(qǐng)求本文中。這個(gè)請(qǐng)求可能會(huì)創(chuàng)建新的資源或修改現(xiàn)有資源,或二者皆有。
5. PUT:向指定資源位置上傳其***內(nèi)容。
6. DELETE:請(qǐng)求服務(wù)器刪除Request-URI所標(biāo)識(shí)的資源。
7. TRACE:回顯服務(wù)器收到的請(qǐng)求,主要用于測(cè)試或診斷。
8. CONNECT:HTTP/1.1協(xié)議中預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器。通常用于SSL加密服務(wù)器的鏈接(經(jīng)由非加密的HTTP代理服務(wù)器)。
方法名稱是區(qū)分大小寫的。當(dāng)某個(gè)請(qǐng)求所針對(duì)的資源不支持對(duì)應(yīng)的請(qǐng)求方法的時(shí)候,服務(wù)器應(yīng)當(dāng)返回狀態(tài)碼405(Method Not Allowed),當(dāng)服務(wù)器不認(rèn)識(shí)或者不支持對(duì)應(yīng)的請(qǐng)求方法的時(shí)候,應(yīng)當(dāng)返回狀態(tài)碼501(Not Implemented)。
HTTP服務(wù)器至少應(yīng)該實(shí)現(xiàn)GET和HEAD方法,其他方法都是可選的。當(dāng)然,所有的方法支持的實(shí)現(xiàn)都應(yīng)當(dāng)符合下述的方法各自的語義定義。此外,除了上述方法,特定的HTTP服務(wù)器還能夠擴(kuò)展自定義的方法。例如:
PATCH(由RFC5789指定的方法):用于將局部修改應(yīng)用到資源。
HTTPS
目前有兩種方法來創(chuàng)建安全超文本協(xié)議連接:HTTPS URI方案和HTTP 1.1請(qǐng)求頭(由RFC2817引入)。由于瀏覽器對(duì)后者的幾乎沒有任何支持,因此HTTPS URI方案仍是創(chuàng)建安全超文本協(xié)議連接的主要手段。安全超文本連接協(xié)議使用https://代替http://
安全方法
對(duì)于GET和HEAD方法而言,除了進(jìn)行獲取資源信息外,這些請(qǐng)求不應(yīng)當(dāng)再有其他意義。也就是說,這些方法應(yīng)當(dāng)被認(rèn)為是“安全的”。 客戶端可能會(huì)使用其他“非安全”方法,例如POST,PUT及DELETE,應(yīng)該以特殊的方式(通常是按鈕而不是超鏈接)告知客戶可能的后果(例如一個(gè)按鈕控制的資金交易),或請(qǐng)求的操作可能是不安全的(例如某個(gè)文件將被上傳或刪除)。
但是,不能想當(dāng)然地認(rèn)為服務(wù)器在處理某個(gè)GET請(qǐng)求時(shí)不會(huì)產(chǎn)生任何副作用。事實(shí)上,很多動(dòng)態(tài)資源會(huì)把這作為其特性。這里重要的區(qū)別在于用戶并沒有請(qǐng)求這一副作用,因此不應(yīng)由用戶為這些副作用承擔(dān)責(zé)任。#p#
副作用
假如在不考慮諸如錯(cuò)誤或者過期等問題的情況下,若干次請(qǐng)求的副作用與單次請(qǐng)求相同或者根本沒有副作用,那么這些請(qǐng)求方法就能夠被視作“冪等”的。GET,HEAD,PUT和DELETE方法都有這樣的冪等屬性,同樣由于根據(jù)協(xié)議,OPTIONS,TRACE都不應(yīng)有副作用,因此也理所當(dāng)然也是冪等的。
假如某個(gè)由若干個(gè)請(qǐng)求做成的請(qǐng)求串行產(chǎn)生的結(jié)果在重復(fù)執(zhí)行這個(gè)請(qǐng)求串行或者其中任何一個(gè)或多個(gè)請(qǐng)求后仍沒有發(fā)生變化,則這個(gè)請(qǐng)求串行便是“冪等”的。但是,可能出現(xiàn)若干個(gè)請(qǐng)求做成的請(qǐng)求串行是“非冪等”的,即使這個(gè)請(qǐng)求串行中所有執(zhí)行的請(qǐng)求方法都是冪等的。例如,這個(gè)請(qǐng)求串行的結(jié)果依賴于某個(gè)會(huì)在下次執(zhí)行這個(gè)串行的過程中被修改的變量。
版本
超文本傳輸協(xié)議已經(jīng)演化出了很多版本,它們中的大部分都是向下兼容的。在RFC2145中描述了HTTP版本號(hào)的用法??蛻舳嗽谡?qǐng)求的開始告訴服務(wù)器它采用的協(xié)議版本號(hào),而后者則在響應(yīng)中采用相同或者更早的協(xié)議版本。
HTTP/0.9
已過時(shí)。只接受GET一種請(qǐng)求方法,沒有在通訊中指定版本號(hào),且不支持請(qǐng)求頭。由于該版本不支持POST方法,因此客戶端無法向服務(wù)器傳遞太多信息。
HTTP/1.0
這是***個(gè)在通訊中指定版本號(hào)的HTTP協(xié)議版本,至今仍被廣泛采用,特別是在代理服務(wù)器中。
HTTP/1.1
當(dāng)前版本。持久連接被默認(rèn)采用,并能很好地配合代理服務(wù)器工作。還支持以管道方式在同時(shí)發(fā)送多個(gè)請(qǐng)求,以便降低線路負(fù)載,提高傳輸速度。
HTTP/1.1相較于HTTP/1.0協(xié)議的區(qū)別主要體現(xiàn)在:
· 緩存處理
· 帶寬優(yōu)化及網(wǎng)絡(luò)連接的使用
· 錯(cuò)誤通知的管理
· 消息在網(wǎng)絡(luò)中的發(fā)送
· 互聯(lián)網(wǎng)地址的維護(hù)
· 安全性及完整性
狀態(tài)碼
所有HTTP響應(yīng)的***行都是狀態(tài)行,依次是當(dāng)前HTTP版本號(hào),3位數(shù)字組成的狀態(tài)代碼,以及描述狀態(tài)的短語,彼此由空格分隔。
狀態(tài)代碼的***個(gè)數(shù)字代表當(dāng)前響應(yīng)的類型:
· 1xx消息——請(qǐng)求已被服務(wù)器接收,繼續(xù)處理
· 2xx成功——請(qǐng)求已成功被服務(wù)器接收、理解、并接受
· 3xx重定向——需要后續(xù)操作才能完成這一請(qǐng)求
· 4xx請(qǐng)求錯(cuò)誤——請(qǐng)求含有詞法錯(cuò)誤或者無法被執(zhí)行
· 5xx服務(wù)器錯(cuò)誤——服務(wù)器在處理某個(gè)正確請(qǐng)求時(shí)發(fā)生錯(cuò)誤
雖然RFC2616中已經(jīng)推薦了描述狀態(tài)的短語,例如"200 OK","404 Not Found",但是WEB開發(fā)者仍然能夠自行決定采用何種短語,用以顯示本地化的狀態(tài)描述或者自定義信息。
持續(xù)連接
在HTTP 0.9和1.0使用非持續(xù)連接,在非持續(xù)連接下,每個(gè)tcp只連接一個(gè)web對(duì)象,連接在每個(gè)請(qǐng)求-回應(yīng)對(duì)后都會(huì)關(guān)閉,一個(gè)連接可被多個(gè)請(qǐng)求重復(fù)利用的保持連接機(jī)制被引入。這種連接持續(xù)化顯著地減少了請(qǐng)求延遲,因?yàn)榭蛻舨挥迷?**請(qǐng)求后再次進(jìn)行TCP交互確認(rèn)創(chuàng)建連接?,F(xiàn)在在HTTP 1.1使用持續(xù)連接,不必為每個(gè)web對(duì)象創(chuàng)建一個(gè)新的連接,一個(gè)連接可以傳送多個(gè)對(duì)象。 HTTP1.1還進(jìn)行了帶寬優(yōu)化,例如1.1引入了分塊傳輸編碼來允許流化傳輸持續(xù)連接上發(fā)送的內(nèi)容,取代原先的buffer式傳輸。HTTP管道允許客戶在上一個(gè)回應(yīng)被收到前發(fā)送多重請(qǐng)求從而進(jìn)一步減少了延遲時(shí)間。
另一項(xiàng)協(xié)議的改進(jìn)是byte serving(字節(jié)服務(wù)),允許服務(wù)器根據(jù)客戶的請(qǐng)求僅僅傳輸資源的一部分。
協(xié)議例子
基本HTTP協(xié)議
下面是一個(gè)HTTP客戶端與服務(wù)器之間會(huì)話的例子,運(yùn)行于www.google.com,端口80
客戶端請(qǐng)求:
GET / HTTP/1.1
Host:www.google.com
(末尾有一個(gè)空行。***行指定方法、資源路徑、協(xié)議版本;第二行是在1.1版里必帶的一個(gè)header作用指定主機(jī))
服務(wù)器應(yīng)答:
HTTP/1.1 200 OK
Content-Length: 3059
Server: GWS/2.0
Date: Sat, 11 Jan 2003 02:44:04 GMT
Content-Type: text/html
Cache-control: private
Set-Cookie:PREF=ID=73d4aef52e57bae9:TM=1042253044:LM=1042253044:S=SMCc_HRPCQiqy
X9j; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/;domain=.google.com
Connection: keep-alive
(緊跟著一個(gè)空行,并且由HTML格式的文本組成了Google的主頁)
AJAX應(yīng)用實(shí)例
AJAX即“Asynchronous JavaScript and XML”(異步的JavaScript與XML技術(shù)),指的是一套綜合了多項(xiàng)技術(shù)的瀏覽器端網(wǎng)頁開發(fā)技術(shù)。傳統(tǒng)的Web應(yīng)用允許用戶端填寫表單(form),當(dāng)提交表單時(shí)就向Web服務(wù)器發(fā)送一個(gè)請(qǐng)求。服務(wù)器接收并處理傳來的表單,然后送回一個(gè)新的網(wǎng)頁,但這個(gè)做法浪費(fèi)了許多帶寬,因?yàn)樵谇昂髢蓚€(gè)頁面中的大部分HTML碼往往是相同的。由于每次應(yīng)用的溝通都需要向服務(wù)器發(fā)送請(qǐng)求,應(yīng)用的回應(yīng)時(shí)間依賴于服務(wù)器的回應(yīng)時(shí)間。這導(dǎo)致了用戶界面的回應(yīng)比本機(jī)應(yīng)用慢得多。與此不同,AJAX應(yīng)用可以僅向服務(wù)器發(fā)送并取回必須的數(shù)據(jù),并在客戶端采用JavaScript處理來自服務(wù)器的回應(yīng)。因?yàn)樵诜?wù)器和瀏覽器之間交換的數(shù)據(jù)大量減少,服務(wù)器回應(yīng)更快了。同時(shí),很多的處理工作可以在發(fā)出請(qǐng)求的客戶端機(jī)器上完成,因此Web服務(wù)器的負(fù)荷也減少了。AJAX不是指一種單一的技術(shù),而是有機(jī)地利用了一系列相關(guān)的技術(shù)。雖然其名稱包含XML,但實(shí)際上數(shù)據(jù)格式可以由JSON代替,進(jìn)一步減少數(shù)據(jù)量,形成所謂的AJAJ。一句話,AJAX基于HTTP協(xié)議。#p#
代碼清單test.html:
- <script src="jquery.js"></script>
- <!-- Javascript -->
- <script type="text/javascript">
- $(document).ready(function (){
- $("#btn392").click(function(){
- var url = "http://www.pureexample.com/backend/ajax_crossdomain.aspx";
- //var url = "http://127.0.0.1:5000";
- //[{ "Manufacturer": "HUMMER", "Sold": 120, "Month": "2012-11"}]
- var success = function(data){
- var html = [];
- data = $.parseJSON(data); /* parse JSON */
- /* loop through array */
- $.each(data, function(index, d){
- html.push("Manufacturer : ", d.Manufacturer, ", ",
- "Sold : ", d.Sold, ", ",
- "Month : ", d.Month, "<br>");
- });
- $("#div391").html(html.join('')).css("background-color", "orange");
- };
- $.ajax({
- type: 'GET',
- url: url,
- data:{todo:"jsonp"},
- dataType: "jsonp",
- crossDomain: true,
- cache:false,
- success: success,
- error:function(jqXHR, textStatus, errorThrown){
- alert(errorThrown);
- }
- });
- });
- });
- </script>
- <!-- HTML -->
- <a name="#jsonp-ajax"></a>
- <div id="example-section39">
- <div>Car sale report</div>
- <div id="div391"></div>
- <button id="btn392" type="button">Click </button>
- </div>
普通情況下雙向抓包信息:
GET /backend/ajax_crossdomain.aspx?callback=jQuery111006746286363340914_1393568973731&todo=jsonp&_=1393568973732HTTP/1.1 Host: www.pureexample.com Connection:keep-alive Accept: */* User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) UbuntuChromium/31.0.1650.63 Chrome/31.0.1650.63 Safari/537.36 Accept-Encoding:gzip,deflate,sdch /* 回包壓縮 */ Accept-Language:zh-CN,zh;q=0.8,en;q=0.6 Cookie:__cfduid=da94308c9f886169fb62c872c48d44e7c1393554685481 HTTP/1.1 200 OK Server:cloudflare-nginx Date: Fri, 28 Feb2014 06:31:01 GMT Content-Type:text/html; charset=utf-8 Transfer-Encoding:chunked Connection:keep-alive Cache-Control:private Vary:Accept-Encoding Set-Cookie:ASP.NET_SessionId=yofjwnenn0cs5ijxx1jrdq55; path=/; HttpOnly X-AspNet-Version:2.0.50727 X-Powered-By:ASP.NET X-Powered-By-Plesk:PleskWin CF-RAY:103b11cb0d290378-LAX Content-Encoding:gzip 78 /* chunck大小為0x78字節(jié)*/ ........... /* 回包為壓縮形式 */ ,M-.4444003713.0363661.44.74.465..47676.P..V..%..........."%+.%.P__.%..dp~N P........+...2204.54T..U....... a ...t..t... 0
通過分析雙向的數(shù)據(jù)包可以看出,若請(qǐng)求頭的Accept-Enconding為gzip,則服務(wù)端的回包會(huì)以壓縮數(shù)據(jù)的形式回傳。#p#
去掉壓縮雙向抓包信息
通過分析雙向的數(shù)據(jù)包可以看出,若請(qǐng)求頭無Accept-Enconding信息,則服務(wù)端的回包會(huì)以普通形式回傳。如果HTTP請(qǐng)求頭為HTTP/1.0則,回應(yīng)信息無Content-Length或CHUNCK的信息字段。
GET /backend/ajax_crossdomain.aspx?callback=jQuery111007808388310950249_1393570158984&todo=jsonp&_=1393570158985HTTP/1.0 Host:www.pureexample.com Connection:keep-alive Accept: */* User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) UbuntuChromium/31.0.1650.63 Chrome/31.0.1650.63 Safari/537.36 Via: 1.1mtnproxy Accept-Language:zh-CN,zh;q=0.8,en;q=0.6 Cookie:__cfduid=da94308c9f886169fb62c872c48d44e7c1393554685481;ASP.NET_SessionId=yofjwnenn0cs5ijxx1jrdq55 HTTP/1.1 200 OK Server:cloudflare-nginx Date: Fri, 28 Feb2014 06:50:16 GMT Content-Type:text/html; charset=utf-8 Connection: close Cache-Control:private X-AspNet-Version:2.0.50727 X-Powered-By:ASP.NET X-Powered-By-Plesk:PleskWin CF-RAY:103b2dfbb05c0378-LAX jQuery111007808388310950249_1393570158984('[{ "Manufacturer":"HUMMER", "Sold":120, "Month":"2012-11"}]')
組成要素
HTTP協(xié)議的展示,需要4個(gè)基本的要素,包括一個(gè)規(guī)范即http協(xié)議本身以及三個(gè)實(shí)體,即資源文件、web服務(wù)器,瀏覽器。http協(xié)議規(guī)范了客戶端與服務(wù)器之間數(shù)據(jù)交互的格式;資源文件包括html,js,css,等展示文件;web服務(wù)器用于存儲(chǔ)資源文件,并響應(yīng)瀏覽器的資源文件請(qǐng)求;瀏覽器從web服務(wù)器上請(qǐng)求資源文件,并解析展示。
圖2 組成元素
如圖1所示,web服務(wù)器接入于公網(wǎng),ip地址為61.155.154.42, url為www.demo.com。 資源文件包括index.html,index.js,index.css,others位于服務(wù)器的虛擬根目錄下,index.html索引文件index.js,index.css。
圖3 資源文件
若用戶在瀏覽器的地址欄中輸入www.demo.com并回車鍵確認(rèn),則將觸發(fā)以下流程:
· 瀏覽器所在客戶端主機(jī)通過DNS查詢,獲取www.demo.com所對(duì)應(yīng)的ip地址,并作為客戶端與該ip地址對(duì)應(yīng)的服務(wù)端建立http連接
· 瀏覽器向服務(wù)器發(fā)起http根請(qǐng)求,瀏覽器從本機(jī)取出根文件index.html并回應(yīng)瀏覽器
· 瀏覽器從根請(qǐng)求回應(yīng)中解析index.html文件中所引入的資源文件列表index.js,index.css等文件
· 瀏覽器再次分別向服務(wù)器發(fā)起index.js,index.css等文件請(qǐng)求
· 瀏覽器獲取所有文件之后,解析渲染出所有資源文件,提供ui接口給用戶
圖4 資源獲取流程#p#
代理服務(wù)
通過以上描述,我們知道,http代理服務(wù)器即是一個(gè)http協(xié)議的中繼。其所完成的任務(wù)是插入瀏覽器與服務(wù)器之間的通信,截獲瀏覽器的http請(qǐng)求,并模擬瀏覽器向服務(wù)器發(fā)起http請(qǐng)求,并把服務(wù)器的http回應(yīng),轉(zhuǎn)回應(yīng)于瀏覽器。這個(gè)動(dòng)作對(duì)應(yīng)瀏覽器來說,是透明的,但是對(duì)于開發(fā)者來說,可以在代理服務(wù)器上做手腳,修改雙向的報(bào)文??梢酝ㄟ^兩種方式來實(shí)現(xiàn)http代理,其一為應(yīng)用程序代理,其二tcp代理,其特征分別為:
應(yīng)用層代理,瀏覽器與代理服務(wù)器,代理服務(wù)器與服務(wù)器兩個(gè)通信組隊(duì)之間,分別建立tcp連接,并進(jìn)行tcp數(shù)據(jù)傳輸。代理服務(wù)器與瀏覽器握手之后,截獲瀏覽器發(fā)出的GET報(bào)文,獲取HOST字段與服務(wù)器握手,并把GET報(bào)文進(jìn)行處理之后,轉(zhuǎn)發(fā)給服務(wù)器,等待服務(wù)器的回包,并轉(zhuǎn)發(fā)給瀏覽器。整個(gè)流程可以在應(yīng)用層完成。
圖5 應(yīng)用層代理服務(wù)器
可以看出代理服務(wù)器對(duì)客戶端上來的GET報(bào)文有修改:1)HTTP/1.1修改為HTTP/1.0, 這樣修改有兩個(gè)作用,服務(wù)器對(duì)HTTP/1.0請(qǐng)求的回應(yīng)報(bào)文沒有Content-Length, 或CHUNCK的標(biāo)示,而這兩個(gè)標(biāo)示與應(yīng)用程序數(shù)據(jù)的長(zhǎng)度相關(guān),如果采用HTTP/1.1的請(qǐng)求,則在修改服務(wù)器的回包之后(回包長(zhǎng)度發(fā)生變化),需要重新修改Content-Length或CHUNCK兩個(gè)屬性的值,而這兩個(gè)值的修改增加了開發(fā)的難度;其二,服務(wù)器對(duì)HTTP/1.0回應(yīng)不會(huì)保持長(zhǎng)連接,即圖中服務(wù)器響應(yīng)index.html之后,tcp連接關(guān)閉,這樣對(duì)于代理軟件來說,軟件容易穩(wěn)定,降低了開發(fā)難度。
· TCP層代理
Ø TCP報(bào)文插入
在TCP層做報(bào)文注入,涉及到了修改報(bào)文雙向sequence, ack-sequence值的問題。原因在于seq值與ack值與實(shí)際報(bào)文長(zhǎng)度相關(guān),如果修改了報(bào)文長(zhǎng)度,顯然需要修改seq, ack值:
圖6 TCP之SEQ與ACK
Ø TCP層代理報(bào)文插入
如圖7所示,代理需要維護(hù)兩個(gè)狀態(tài)機(jī),收到服務(wù)端帶fin報(bào)文的數(shù)據(jù)包之后,和服務(wù)端完成結(jié)束握手;同時(shí)去除fin報(bào)文的fin標(biāo)志,把改報(bào)文發(fā)給瀏覽器,同時(shí)完成和瀏覽器的報(bào)文插入以及結(jié)束握手:
圖7 TCP之SEQ與ACK
Ø TCP層代理狀態(tài)機(jī)
1. Eth0收到http報(bào)文的結(jié)束幀(帶fin)
2. 代理去掉fin標(biāo)志
3. 代理插入一段報(bào)文,并加上fin標(biāo)志
4.瀏覽器對(duì)原始的http結(jié)束報(bào)文回應(yīng)fin:
問題:看起來服務(wù)器到瀏覽器的fin報(bào)文,并沒有被代理扔掉,故而瀏覽器收到了兩幀fin報(bào)文。