日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

HTTP代理如何正确处理Cookie

發(fā)布時間:2025/3/20 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HTTP代理如何正确处理Cookie 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

HTTP代理如何正確處理Cookie http://hi.baidu.com/injava/blog/item/e08454a7ce261f90d14358df.html 2008-06-30 15:53
大多數(shù)的 Web 應(yīng)用程序都要求維護某種會話狀態(tài),如用戶購物車的內(nèi)容。這種會話狀態(tài)的保持很多情況下需要借助于Cookie或者Session的幫助。本文結(jié)合在線頁面翻譯 (Machine Translation System)項目中對于Cookie的處理方法,探討一下如何在HTTP應(yīng)用代理中正確處理Cookie的傳遞和管理問題。

讀者定位為具有Java和Web開發(fā)經(jīng)驗的開發(fā)和設(shè)計人員。

讀者可以學習到關(guān)于Cookie的工作原理和Cookie協(xié)議的細節(jié),以及在一個HTTP應(yīng)用代理的場景下Cookie的管理和處理思想,并可以直接使用文中的代碼和思路,提高工作效率。

隨著越來越多的系統(tǒng)移植到了Web上,HTTP協(xié)議具有了比以前更廣泛的應(yīng)用。不同的系統(tǒng)對WEB實現(xiàn)提出了不同的要求,基于HTTP協(xié)議的網(wǎng)絡(luò)應(yīng)用正趨于復(fù)雜化和多元化。很多應(yīng)用需要把用戶請求的頁面進行處理后再返回給用戶,比如頁面關(guān)鍵字過濾,頁面內(nèi)容緩存、內(nèi)容搜索、頁面翻譯等等。這些應(yīng)用在實際效果上類似于一個HTTP應(yīng)用代理:它們首先接受用戶的請求,根據(jù)用戶請求的URL去真正的目標服務(wù)器取回目標頁面,再根據(jù)不同應(yīng)用的要求做出相應(yīng)處理后返回給用戶。這樣用戶直接面對的就是這個HTTP應(yīng)用代理,而通過它與其他頁面進行交互。Cookie或Session技術(shù)的應(yīng)用,解決了HTTP協(xié)議的一個問題 -- 無法保持客戶狀態(tài),因此它現(xiàn)在被廣泛應(yīng)用于各種Web站點中。上面提到的那些應(yīng)用如果不能處理好Cookie和Session的傳遞、更新和廢除等問題,就會極大的限制它們所能處理站點的范圍,因此如何在HTTP應(yīng)用代理中正確處理Cookie,成為一個必須解決的問題。本文結(jié)合在頁面翻譯(Machine Translation System)項目中對于Cookie的處理方法,探討一下這方面的解決方案。

Machine Translation System(以下簡稱MTS)是一個在線實時頁面翻譯系統(tǒng),為用戶在線提供把英文頁面翻譯成其他9種語言的服務(wù)。用戶通過向MTS系統(tǒng)提交一個類似下面的URL使用此服務(wù),其中參數(shù)url指明了用戶所需要翻譯的目標地址,參數(shù)language指明了所需翻譯成的目標語言,www.mts.com是假想中提供MTS服務(wù)的站點。

HTTP://www.mts.com/translate?url=http://www.ibm.com/&language=French

一個完整的MTS系統(tǒng)處理過程可以分解成以下幾個步驟:

  • 用戶向MTS提交合適的URL。
  • MTS在接到用戶的請求后,解析出用戶需要翻譯的目標地址和目標語言,根據(jù)用戶請求的目標地址,把請求轉(zhuǎn)發(fā)到目標服務(wù)器。
  • MTS接受來自目標服務(wù)器的應(yīng)答,包括頁面信息和HTTP頭信息。
  • MTS在確定得到正確的目標頁面后,把頁面內(nèi)容送入WebSphere Translation Server進行翻譯。
  • 把翻譯后的頁面連同修改后的HTTP頭信息提交給用戶。


?

?


當然,這其中涉及到很多的應(yīng)用處理。比如與各種HTTP/HTTPS站點建立聯(lián)結(jié)、根據(jù)HTTP頭信息進行頁面跳轉(zhuǎn)和錯誤處理、為始終保持用戶在翻譯模式下而對目標的HTML頁面進行分析和修改,根據(jù)系統(tǒng)設(shè)置對某些DNT(Do Not Translate)的頁面進行過濾和跳轉(zhuǎn),當然還有對Cookie的處理等等。其他問題跟這篇文章關(guān)聯(lián)不大,我們重點討論在這種情況下的Cookie處理。Cookie跟隨目標服務(wù)器的HTTP頭信息被MTS接收到,經(jīng)過MTS整理之后發(fā)給客戶端瀏覽器。MTS在接到下一次用戶對同一個站點的翻譯請求時,再把從客戶端得到的Cookie發(fā)送給目標服務(wù)器。

在以上的場景中,MTS充當?shù)淖饔妙愃朴谝环NHTTP應(yīng)用代理服務(wù)器,它代替用戶取得目標頁面,并在作出相應(yīng)處理后再提交給用戶。當然,這種代理服務(wù)器不需要用戶修改瀏覽器的代理服務(wù)器參數(shù)或者網(wǎng)絡(luò)配置,而只是簡單的在瀏覽器的地址欄中輸入一個MTS能夠識別的URL即可。此篇文章也是在這樣一個應(yīng)用場景的基礎(chǔ)上,展開對HTTP應(yīng)用代理服務(wù)器如何處理Cookie的討論。

在MTS系統(tǒng)中,目標服務(wù)器的Cookie在兩個地方會產(chǎn)生問題。當MTS接收目標服務(wù)器應(yīng)答的時候,Cookie隨著HTTP頭信息被MTS接收到的。這時候目標服務(wù)器認為MTS就是最終客戶,因此它賦予了Cookie與目標服務(wù)器相符的屬性。而如果MTS把這些Cookie原封不動的保存在HTTP頭信息中,傳給真正的最終用戶的話,用戶的瀏覽器會因為這些Cookie不合法而忽略它們。同理,當Cookie從瀏覽器端傳回目標服務(wù)器的時候,也會遇到相同的問題。因此有必要對Cookie進行一些處理,以保證用戶的瀏覽器能真正識別和利用這些Cookie。

但是為何用戶瀏覽器無法識別從目標服務(wù)器傳過來的原始Cookie呢?這是因為出于安全性的考慮,Cookie規(guī)范制定的時候?qū)ookie的產(chǎn)生和接受設(shè)置了一些嚴格的規(guī)范,不符合這些規(guī)范的Cookie,瀏覽器和服務(wù)器都將予以忽略。下面我們從Cookie規(guī)范入手進行介紹。

目前有以下幾種Cookie規(guī)范:

  • Netscape cookie草案:是最早的cookie規(guī)范,基于rfc2109。盡管這個規(guī)范與rc2109有較大的差別,但是很多服務(wù)器都與之兼容。
  • rfc2109, 是w3c發(fā)布的第一個官方cookie規(guī)范。理論上講,所有的服務(wù)器在處理cookie(版本1)時,都要遵循此規(guī)范。遺憾的是,這個規(guī)范太嚴格了,以致很多服務(wù)器不正確的實施了該規(guī)范或仍在使用Netscape規(guī)范。
  • rfc2965規(guī)范定義了cookie版本2,并說明了cookie版本1的不足。

rfc2965規(guī)范的使用,目前并不多。rfc2109規(guī)范相應(yīng)要嚴格得多,在實際應(yīng)用上,并不是所有的瀏覽器和Web服務(wù)器都嚴格遵守。因此相比較而言,Netscape cookie草案倒是一個比較簡潔和被廣泛支持的Cookie規(guī)范,因此我們在這里以Netscape cookie草案為基礎(chǔ)進行討論,對于其他兩種規(guī)范,我們的討論和代碼具有相同的意義。關(guān)于Netscape cookie草案的細節(jié),大家可以參照Netscape官方站點,這里我們列舉一些和我們討論有關(guān)的內(nèi)容。

根據(jù)Netscape cookie草案的描述,Cookie 是Web 服務(wù)器向用戶的瀏覽器發(fā)送的一段ASCII碼文本。一旦收到Cookie,瀏覽器會把Cookie的信息片斷以"名/值"對(name-value pairs)的形式儲存保存在本地。這以后,每當向同一個Web 服務(wù)器請求一個新的文檔時,Web 瀏覽器都會發(fā)送之站點以前存儲在本地的Cookie。創(chuàng)建Cookie的最初目的是想讓Web服務(wù)器能夠通過多個HTTP請求追蹤客戶。有些復(fù)雜的網(wǎng)絡(luò)應(yīng)用需要在不同的網(wǎng)頁之間保持一致,它們需要這種會話狀態(tài)的保持能力。

瀏覽器與Web服務(wù)器通過HTTP協(xié)議進行通訊,而Cookie就是保存在HTTP協(xié)議的請求或者應(yīng)答頭部(在HTTP協(xié)議中,數(shù)據(jù)包括兩部分,一部分是頭部,由一些名值對構(gòu)成,用來描述要被傳輸數(shù)據(jù)的一些信息。一部分是主體(body),是真正的數(shù)據(jù)(如HTML頁面等))進行傳送的。

在HTML文檔被發(fā)送之前,Web服務(wù)器通過傳送HTTP 包頭中的Set-Cookie 消息把一個cookie 發(fā)送到用戶的瀏覽器中。下面是一個遵循Netscape cookie草案的完整的Set-Cookie 頭:


Set-Cookie:customer=huangxp; path=/foo; domain=.ibm.com; expires= Wednesday, 19-OCT-05 23:12:40 GMT; [secure]

Set-Cookie的每個屬性解釋如下:

  • Customer=huangxp 一個"名稱=值"對,把名稱customer設(shè)置為值"huangxp",這個屬性在Cookie中必須有。
  • path=/foo 控制哪些訪問能夠觸發(fā)cookie 的發(fā)送。如果沒有指定path,cookie 會在所有對此站點的HTTP 傳送時發(fā)送。如果path=/directory,只有訪問/directory 下面的網(wǎng)頁時,cookie才被發(fā)送。在這個例子中,用戶在訪問目錄/foo下的內(nèi)容時,瀏覽器將發(fā)送此cookie。如果指定了path,但是path與當前訪問的url不符,則此cookie將被忽略。
  • domain=.ibm.com 指定cookie被發(fā)送到哪臺計算機上。正常情況下,cookie只被送回最初向用戶發(fā)送cookie 的計算機。在這個例子中,cookie 會被發(fā)送到任何在.ibm.com域中的主機。如果domain 被設(shè)為空,domain 就被設(shè)置為和提供cookie 的Web 服務(wù)器相同。如果domain不為空,并且它的值又和提供cookie的Web服務(wù)器域名不符,這個Cookie將被忽略。
  • expires= Wednesday, 19-OCT-05 23:12:40 GMT 指定cookie 失效的時間。如果沒有指定失效時間,這個cookie 就不會被寫入計算機的硬盤上,并且只持續(xù)到這次會話結(jié)束。
  • secure 如果secure 這個詞被作為Set-Cookie 頭的一部分,那么cookie 只能通過安全通道傳輸(目前即SSL通道)。否則,瀏覽器將忽略此Cookie。

一旦瀏覽器接收了cookie,這個cookie和對遠端Web服務(wù)器的連續(xù)請求將一起被瀏覽器發(fā)送。例如 前一個cookie 被存入瀏覽器并且瀏覽器試圖請求 URL http://www.ibm.com/foo/index.html 時,下面的HTTP 包頭就被發(fā)送到遠端的Web服務(wù)器。

GET /foo/index.html HTTP/1.0
Cookie:customer=huangxp


一次典型的網(wǎng)絡(luò)瀏覽過程

在了解了Cookie協(xié)議的一些基本內(nèi)容之后,讓我們看看一次典型的網(wǎng)絡(luò)瀏覽過程中瀏覽器如何識別和處理Cookie:

  • 瀏覽器對于Web服務(wù)器應(yīng)答包頭中Cookie的操作步驟:
    1. 從Web服務(wù)器的應(yīng)答包頭中提取所有的cookie。
    2. 解析這些cookie的組成部分(名稱,值,路徑等等)。
    3. 判定主機是否允許設(shè)置這些cookie。允許的話,則把這些Cookie存儲在本地。
  • 瀏覽器對Web服務(wù)器請求包頭中所有的Cookie進行篩選的步驟:
    1. 根據(jù)請求的URL和本地存儲cookie的屬性,判斷那些Cookie能被發(fā)送給Web服務(wù)器。
    2. 對于多個cookie,判定發(fā)送的順序。
    3. 把需要發(fā)送的Cookie加入到請求HTTP包頭中一起發(fā)送。

以上我們了解了在一個典型的瀏覽器與Web服務(wù)器交互的時候,Cookie的傳遞過程。下面我們將看到,如果在MTS代理網(wǎng)絡(luò)瀏覽的過程中,不對Cookie進行修改,上面的Cookie傳遞過程將無法實現(xiàn)。

1. 假設(shè)用戶希望把 http://www.ibm.com/foo/index.html 頁面翻譯成法文,應(yīng)該使用如下的url對MTS發(fā)出請求

http://www.mts.com/translate?url=http://www.ibm.com/foo/index.html&language=French

2. MTS接收用戶的請求,連接遠程目標服務(wù)器 http://www.ibm.com/foo/index.html。目標服務(wù)器做出應(yīng)答,返回HTTP頭和HTML頁面內(nèi)容。其中,典型的HTTP頭內(nèi)容如下:


HTTP/1.1 200 OK Date: Mon, 24 Oct 2005 06:54:41 GMT Server: IBM_HTTP_Server Cache-Control: no-cache Content-Length: 19885 Connection: close Set-Cookie:customer=huangxp; path=/foo; domain=.ibm.com; expires= Wednesday, 19-OCT-05 23:12:40 GMT Content-Type: text/html

3. MTS不對Set-Cookie后的內(nèi)容作任何處理,直接把它加到用戶瀏覽器的應(yīng)答頭上發(fā)送給瀏覽器。

4. 瀏覽器將從Set-Cookie中解析出domain和path的值,分別是.ibm.com和/foo,并與請求的url:http://www.mts.com/translate?url=http://www.ibm.com/foo/index.html&language=French進行比較。請求url的domain是www.mts.com,path是/,與Set-Cookie中的屬性不符,所以瀏覽器將忽略此Cookie。

另外,在瀏覽器發(fā)送Cookie的時候也會遇到同樣的問題,同樣如上例,如果瀏覽器里本來已經(jīng)存儲了http://www.ibm.com/foo/的Cookie,但由于用戶要通過MTS訪問此站點,瀏覽器經(jīng)不會把已經(jīng)存儲的Cookie上轉(zhuǎn)到MTS中,MTS也就無法把之傳遞到http://ibm.com/foo/上。

基于上面Cookie規(guī)范的介紹和例證,我們能看出,瀏覽器在接受某一個站點的Cookie的時候,需要檢查Cookie的參數(shù)domain、path、secure,看是否與當前的站點和URL相符,如果不符的話,就會忽略。另一方面。瀏覽器在上傳Cookie的時候,也會根據(jù)當前所訪問站點的屬性,上傳相關(guān)的Cookie,而其他的Cookie則不予上傳。

至此,我們討論了需要修改Cookie的根本原因在于Cookie規(guī)范的限制。下面我們討論兩種解決問題的思路。

Cookie的存在是要解決HTTP協(xié)議本身先天的缺陷-無狀態(tài)性,它為用戶保存了一些需要的狀態(tài)信息。因此我們解決此問題的最本質(zhì)的出發(fā)點,也就是找到一種途徑能為用戶保存Cookie所提供用戶狀態(tài)信息,實際上就是Name/Value對。

第一種思路就是修改目標服務(wù)器取得的Cookie,使之符合MTS站點的屬性,然后作為MTS站點的Cookie存儲到用戶的瀏覽器中去。當然,這種修改必須保留原始Cookie的所有屬性值,當以后訪問同一個目標服務(wù)器的時候,MTS能根據(jù)保存的屬性值還原出原始Cookie,然后進行提交。

具體到屬性值的保存位置,沒有太多選擇的余地,實際上,domain,path,secure,expires這幾個屬性都無法利用,只有利用name=value這一屬性對。我們的做法是創(chuàng)造一個新的Cookie,把原始Cookie的domain,path的值與name值進行編碼,用分隔符附加在Name值的后面,符值給新的Cookie。這樣做也同時避免了不同目標服務(wù)器如果出現(xiàn)同名的Cookie,將會互相覆蓋的情況(Cookie規(guī)范里面也規(guī)定了,客戶端以domain,path,name作為Cookie的唯一標示)。而原始Cookie的secure和expires值,直接符給新的Cookie,新Cookie的domain和path設(shè)成缺省值,這樣,新Cookie就可以被瀏覽器正常接受。由于瀏覽器接受的所有Cookie的domain和path值都一樣,因此每次用戶對MTS提出請求時,瀏覽器都會把所有與MTS站點相關(guān)的Cookie上傳,因此,MTS還需要還原原始的Cookie,過濾掉與目標服務(wù)器不相干的Cookie,然后上傳有用的Cookie。

這種思路的優(yōu)點在于Cookie存儲在客戶端,可以做到長期存儲,瀏覽器自己根據(jù)Cookie的expires值做出判斷,省掉很多開發(fā)的麻煩。缺點是轉(zhuǎn)換的過程相對較復(fù)雜。另外還有一個缺點,也是由于Cookie規(guī)范的限制所造成的。Cookie規(guī)范對于一個瀏覽器同時能夠存儲的Cookie數(shù)量作出了規(guī)定。

  • 總共300 個cookie
  • 每個Cookie 4 K 的存儲容量
  • 每一個domain 或者 server 20 個cookie。

以上是瀏覽器所應(yīng)達到的最小存儲數(shù)量,超出這個限制,瀏覽器應(yīng)該自動按照最少最近被使用的原則刪除超出得Cookie。由于用戶有可能通過MTS這一個網(wǎng)站翻譯大量的目標服務(wù)器,因此瀏覽器存儲在MTS的domain下的cookie數(shù)量就很有可能超過20個,這時候就會導(dǎo)致某些Cookie被刪除。一般這也不會造成太大問題,因為規(guī)范是要求瀏覽器刪除最少最近被使用的Cookie,但我們在實際測試當中發(fā)現(xiàn)有些瀏覽器并不遵守這樣的規(guī)范,而是刪除最新的Cookie,這就將導(dǎo)致用戶很大的不便。

第二種思路在于把原始的Cookie組織成dataBean,存儲到用戶的Session當中去。這樣,在用戶端只需要存儲一個SessionID的Cookie,而不需要存儲所有目標服務(wù)器的每一個Cookie。另外,當接收到用戶的又一次翻譯請求時,再從Session當中取出所有的dataBean,逐一進行分析,找出與用戶所請求的目標服務(wù)器相符的原始Cookie,進行提交。

這種思路可以克服上一種思路中Cookie超過標準數(shù)量時的缺陷,而且不需編碼保存原始的Cookie屬性值,減少了程序的復(fù)雜度。缺點是需要程序員自己處理expires。而且由于是把Cookie存儲在Session中,一旦Session失效,所有Cookie都將被刪除,所以,無法保存那些長期的Cookie。

總之,兩種思路各有利弊,在實際應(yīng)用當中要權(quán)衡考慮。下面我們針對兩種思路進行技術(shù)實現(xiàn),分別對應(yīng)方案一和方案二。

由于MTS需要與目標服務(wù)器連接,遵循HTTP協(xié)議讀取和返回Cookie,但是如果用JDK中的java.net.URLConnection處理Cookie將非常不方便,因此我們使用HTTPClient來處理與目標服務(wù)器的連接。

用戶每發(fā)起一次新的請求,瀏覽器在檢查完本地存儲Cookie的有效性后,會把所有由MTS產(chǎn)生的有效Cookie附加在請求頭里送到MTS。MTS接受到客戶端的翻譯請求后,從Request中提取出所有的Cookie,還原后根據(jù)目標服務(wù)器的domain和path進行過濾。產(chǎn)生所有與目標服務(wù)器相關(guān)的Cookie。


//從request中獲取所有的Cookie javax.servlet.http.Cookie[] theCookies = request.getCookies(); ArrayList cookiesList = new ArrayList(); String url = request.getParameter("url"); String domain = URLUtil.getURLHost(url); String path = URLUtil.getPath(url); if (theCookies != null) {for (int i = 0; i < theCookies.length; i++){RE r = new RE();//用正則表達式把name項還原成domain,path,nameREDebugCompiler compiler = new REDebugCompiler();r.setProgram(compiler.compile("//|//|"));String[] values = r.split(theCookies[i].getName());//"9.181.116.183||/MTModule||testCookie:value1" or " || ||testCookie:value1"if (values.length == 3){if (values[0].trim().startsWith(".")){if (!domain.endsWith(values[0].trim()))continue;} else if (!domain.endsWith("://" + values[0].trim()))continue;if (!path.startsWith(values[1].trim()))continue;Cookie tempCookie = new Cookie();tempCookie.setDomain(("".equals(values[0].trim())) ? null : values[0]);tempCookie.setPath(("".equals(values[1].trim())) ? null : values[1]);tempCookie.setName(("".equals(values[2].trim())) ? null : values[2]);tempCookie.setSecure(theCookies[i].getSecure());tempCookie.setValue(theCookies[i].getValue());tempCookie.setVersion(theCookies[i].getVersion());tempCookie.setComment(theCookies[i].getComment());cookiesList.add(tempCookie);}} } //transferedCookie用來存儲將被傳到目標服務(wù)器的Cookie Cookie[] transferedCookie = new Cookie[cookiesList.size()]; cookiesList.toArray(transferedCookie);

接下來,需要把Cookie送到目標服務(wù)器中。我們使用HTTPClient與目標服務(wù)器連接。HTTPClient在與目標服務(wù)器連接以后,允許服務(wù)器設(shè)置Cookie并在需要的時候自動將Cookie返回服務(wù)器,也支持手工設(shè)置 Cookie后發(fā)送到服務(wù)器端。但是,由于如何處理cookie有幾個規(guī)范互相沖突:Netscape Cookie 草案、RFC2109、RFC2965,而且還有很大數(shù)量的軟件商的Cookie實現(xiàn)不遵循任何規(guī)范。 為了處理這種狀況,需要把HttpClient設(shè)置成Cookie兼容模式,這樣可以最大限度的處理好各種Cookie。下面的代碼把Cookie送到目標服務(wù)器。


HttpClient client = new HttpClient(); //從request得到所有需要傳輸?shù)腸ookie Cookie[] questCookie = getCookieFromRequest(request); //設(shè)置HTTPClient為Cookie兼容模式 client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY); if (questCookie.length > 0) //把Cookie加到httpclient中client.getState().addCookies(questCookie); HttpMethod method = new GetMethod(TagerURL);//向目標服務(wù)器發(fā)送請求 int statusCode = client.executeMethod(method); method.releaseConnection();

MTS把請求和Cookie送出后,繼續(xù)接收目標服務(wù)器的應(yīng)答,讀取返回的原始Cookie,并轉(zhuǎn)換成可以存儲在用戶瀏覽器端的Cookie。下面的代碼將對原始Cookie的內(nèi)容進行變換,保留expires和secure等項,把domain和path項編碼到name中去。


//從HTTPClient中取得所有的Cookie Cookie[] temp = client.getState().getCookies(); if (temp != null) {javax.servlet.httpCookie theCookie = new javax.servlet.http.Cookie[temp.length];//逐一對Cookie進行處理for (int i = 0; i < temp.length; i++){ StringBuffer sb = new StringBuffer();//編碼成domain||path||namesb.append(temp[i].getDomain() == null ? " " : temp[i].getDomain());sb.append("||");sb.append(temp[i].getPath() == null ? " " : temp[i].getPath());sb.append("||");sb.append(temp[i].getName() == null ? " " : temp[i].getName());theCookie[i] =new Cookie(sb.toString(),temp[i].getValue());//復(fù)制其他項theCookie[i].setMaxAge(theCookie[i].getMaxAge();theCookie[i].setSecure(temp[i].getSecure());theCookie[i].setVersion(temp[i].getVersion());theCookie[i].setComment(temp[i].getComment());} }

最后一步,把這些Cookie保存到response里,隨HTTP應(yīng)答頭返回用戶瀏覽器。并保存在瀏覽器中。


//把所有轉(zhuǎn)換后的Cookie加入response for (int i = 0; i < theCookie.length; i++) {response.addCookie(theCookie[i]); }

至此,我們已經(jīng)完成了接收用戶請求,轉(zhuǎn)換Cookie,發(fā)送到目標服務(wù)器,接收目標服務(wù)器的原始Cookie,并保存在客戶瀏覽器的整個處理過程。


在此種方案中,目標服務(wù)器返回給MTS的Cookie將被組織成dataBean,存儲在用戶的Session中。因此,我們首先生成一個用來存儲Cookie的類CookiesBean,根據(jù)它的特性,它可以繼承ArraryList類。此對象將存儲用戶訪問目標服務(wù)器時接收到的所有Cookie,并提供與新接收到的Cookie融合的功能,同時能夠刪除過期的Cookie,更新同名的Cookie。


public class CookiesBean extends ArrayList {/*** 處理Cookies.* @參數(shù) Cookies array*/public CookiesBean(Cookie[] cook){if (cook == null)return; //add all cookie which isn't expired.for (int i = 0; i < cook.length; i++){if (!cook[i].isExpired()){add(cook[i]);}}}/*** 融合參數(shù)中的bean* @參數(shù) bean* 參考: rfc2109 4.3.3 Cookie Management*/public void RefreshBean(CookiesBean bean){if (bean == null)return;Iterator it = bean.iterator();//針對bean中的每一個Cookie進行處理while (it.hasNext()){Cookie beanCookie = (Cookie) it.next();if (beanCookie == null) continue;ArrayList drop = new ArrayList();Iterator thisIt = iterator();//取出存儲的Cookie進行比較和處理while (thisIt.hasNext()){Cookie thisCookie = (Cookie) thisIt.next();if (thisCookie == null) continue;//比較name,domain和path,如果一樣的話,則把此Cookie移到drop中if (CommonMethods.CompString(beanCookie.getName(), thisCookie.getName())&& CommonMethods.CompString(beanCookie.getDomain(),thisCookie.getDomain())&& CommonMethods.CompString(beanCookie.getPath(),thisCookie.getPath())){drop.add(thisCookie);continue;}//刪除過期的Cookieif (thisCookie.isExpired())drop.add(thisCookie);}//刪除所有drop中的Cookiethis.removeAll(drop);//如果beanCookie有效,則加入到存儲區(qū)中。if (!beanCookie.isExpired())add(beanCookie);}return;} }

當MTS接受到客戶端的翻譯請求后,會從Session中提取出所有的dataBean,并得到存儲的所有Cookie。如以下代碼:


CookiesBean dataBean = null;Cookie[] theCookies = new Cookie[0];ArrayList cookiesList = new ArrayList();//獲得Session,并獲得dataBeanHttpSession session = request.getSession(false);if (session != null){dataBean = (CookiesBean) session.getAttribute(SESSION_NAME);}else{return theCookies;}

MTS在所有的存儲的Cookie中,檢查Cookie的Domain、path和secure的值,篩選出符合目標服務(wù)器的Cookie。


//提取目標服務(wù)器的domain和pathString url = context.getURL();String domain = URLUtil.getURLHost(url);String path = url.substring(domain.length());String cookiedomain = null;String cookiepath = null;//逐個比較Cookie的domain和path//把符合要求的Cookie紀錄到cookiesList中for (int i = 0; i < dataBean.size(); i++){Cookie cookie = (Cookie) dataBean.get(i);if (cookie == null) continue;cookiedomain =(cookie.getDomain() == null) ? "" : cookie.getDomain();cookiepath = (cookie.getPath() == null) ? " " : cookie.getPath();if (!path.startsWith(cookiepath))continue;if (cookiedomain.startsWith(".")){if (!domain.endsWith(cookiedomain))continue;}else if (!domain.endsWith("://" + cookiedomain))continue;if (cookie.isExpired())continue;if (cookie.getSecure() && url.toLowerCase().startsWith("http:"))continue;cookiesList.add(cookie);}theCookies = new Cookie[cookiesList.size()];cookiesList.toArray(theCookies);return theCookies;

把Cookie送到目標服務(wù)器的代碼與方案一基本一樣,在此忽略。

最后一步,需要把Cookie存儲到Session中。下面的代碼將從目標服務(wù)器接受Cookie,融入到dataBean中,并保存到客戶的Session中。


//從目標服務(wù)器得到Cookie集Cookie[] cookies = client.getState().getCookies();CookiesBean bean = new CookiesBean(cookies);CookiesBean dataBean = bean;//取得用戶SessionHttpSession session = request.getSession(false);if (session != null){if (session.getAttribute(SESSION_NAME) != null){//讀取Session中存取的dataBeandataBean = (CookiesBean) session.getAttribute(SESSION_NAME);//目標服務(wù)器端的Cookie融合到Session中的dataBean中dataBean.RefreshBean(bean);}//把最終的dataBean存入Session中session.setAttribute(SESSION_NAME, dataBean);}

至此,我們已經(jīng)完成了在Session中保存?zhèn)€目標服務(wù)器所產(chǎn)生Cookie的整個處理過程。

在研究完如何管理和傳遞Cookie之后,我們也需要研究一下Session的傳遞。因為目前大部分站點都在采用Session機制保存用戶狀態(tài)數(shù)據(jù),如果不能解決Session的傳遞問題,HTTP應(yīng)用代理服務(wù)器的適用范圍同樣會大打折扣。

首先我們了解一下Session的實現(xiàn)機制。Session是一種服務(wù)器端的機制,服務(wù)器使用一種類似于散列表的結(jié)構(gòu)來保存信息。當程序需要為某個客戶端的請求創(chuàng)建一個session的時候,服務(wù)器首先檢查這個客戶端的請求里是否已包含了一個session標識 - 稱為session id,如果已包含一個session id則說明以前已經(jīng)為此客戶端創(chuàng)建過session,服務(wù)器就按照session id把這個session檢索出來使用(如果檢索不到,可能會新建一個),session id的值應(yīng)該是一個既不會重復(fù),又不容易被找到規(guī)律以仿造的字符串。

保存這個session id的方式之一就是采用Cookie。一般這個Cookie的名字都類似于 SESSIONID。比如WebSphere對于Web應(yīng)用程序生成的Cookie:JSESSIONID= 0001HWF4iVD94pY8Cpbx6U4CXkf:10lro0398,它的名字就是 JSESSIONID。

保存session id的其他方式還包括URL重寫和表單隱藏字段。這兩種方式都不需要代理服務(wù)器作特殊處理。因此實際上,我們解決了Cookie的管理和傳遞的問題之后,也就解決了Session的管理和傳遞。



從上面的討論中可以看出,由于Cookie本身的規(guī)范限制,HTTP應(yīng)用代理所必需面對的一個問題就是如何對Cookie進行正確的處理。本文對此提出了兩種解決思路并列出了實現(xiàn)代碼。對于MTS項目本身,我們使用的是第二種方案。開發(fā)人員在認識好Cookie本身的特性之后,參照本文的思路,根據(jù)自己系統(tǒng)的特點,也會找出更適宜的解決方案。

?

總結(jié)

以上是生活随笔為你收集整理的HTTP代理如何正确处理Cookie的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。