session-理解HTTP session原理及應(yīng)用

轉(zhuǎn)自 :http://blog.csdn.net/taoff/articles/1921009.aspx

一睹欲、術(shù)語(yǔ)session
在我的經(jīng)驗(yàn)里堤结,session這個(gè)詞被濫用的程度大概僅次于transaction剃幌,更加有趣的是transaction與session在某些語(yǔ)境下的含義是相同的脐供。

session拓颓,中文經(jīng)常翻譯為會(huì)話,其本來(lái)的含義是指有始有終的一系列動(dòng)作/消息关筒,比如打電話時(shí)從拿起電話撥號(hào)到掛斷電話這中間的一系列過(guò)程可以稱之為一個(gè)session溶握。有時(shí)候我們可以看到這樣的話“在一個(gè)瀏覽器會(huì)話期間,...”蒸播,這里的會(huì)話一詞用的就是其本義睡榆,是指從一個(gè)瀏覽器窗口打開(kāi)到關(guān)閉這個(gè)期間 ①。最混亂的是“用戶(客戶端)在一次會(huì)話期間”這樣一句話袍榆,它可能指用戶的一系列動(dòng)作(一般情況下是同某個(gè)具體目的相關(guān)的一系列動(dòng)作胀屿,比如從登錄到選購(gòu)商品到結(jié)賬登出這樣一個(gè)網(wǎng)上購(gòu)物的過(guò)程,有時(shí)候也被稱為一個(gè)transaction)蜡塌,然而有時(shí)候也可能僅僅是指一次連接碉纳,也有可能是指含義①勿负,其中的差別只能靠上下文來(lái)推斷②馏艾。

然而當(dāng)session一詞與網(wǎng)絡(luò)協(xié)議相關(guān)聯(lián)時(shí)劳曹,它又往往隱含了“面向連接”和/或“保持狀態(tài)”這樣兩個(gè)含義,“面向連接”指的是在通信雙方在通信之前要先建立一個(gè)通信的渠道琅摩,比如打電話铁孵,直到對(duì)方接了電話通信才能開(kāi)始,與此相對(duì)的是寫信房资,在你把信發(fā)出去的時(shí)候你并不能確認(rèn)對(duì)方的地址是否正確蜕劝,通信渠道不一定能建立,但對(duì)發(fā)信人來(lái)說(shuō)轰异,通信已經(jīng)開(kāi)始了岖沛。“保持狀態(tài)”則是指通信的一方能夠把一系列的消息關(guān)聯(lián)起來(lái)搭独,使得消息之間可以互相依賴婴削,比如一個(gè)服務(wù)員能夠認(rèn)出再次光臨的老顧客并且記得上次這個(gè)顧客還欠店里一塊錢。這一類的例子有“一個(gè)TCP session”或者“一個(gè)POP3 session”③牙肝。

而到了web服務(wù)器蓬勃發(fā)展的時(shí)代唉俗,session在web開(kāi)發(fā)語(yǔ)境下的語(yǔ)義又有了新的擴(kuò)展,它的含義是指一類用來(lái)在客戶端與服務(wù)器之間保持狀態(tài)的解決方案 ④配椭。有時(shí)候session也用來(lái)指這種解決方案的存儲(chǔ)結(jié)構(gòu)虫溜,如“把xxx保存在session里”⑤。由于各種用于web開(kāi)發(fā)的語(yǔ)言在一定程度上都提供了對(duì)這種解決方案的支持股缸,所以在某種特定語(yǔ)言的語(yǔ)境下衡楞,session也被用來(lái)指代該語(yǔ)言的解決方案,比如經(jīng)常把Java里提供的javax.servlet.http.HttpSession簡(jiǎn)稱為session⑥敦姻。

鑒于這種混亂已不可改變寺酪,本文中session一詞的運(yùn)用也會(huì)根據(jù)上下文有不同的含義,請(qǐng)大家注意分辨替劈。
在本文中寄雀,使用中文“瀏覽器會(huì)話期間”來(lái)表達(dá)含義①,使用“session機(jī)制”來(lái)表達(dá)含義④陨献,使用“session”表達(dá)含義⑤盒犹,使用具體的“HttpSession”來(lái)表達(dá)含義⑥

二、HTTP協(xié)議與狀態(tài)保持
HTTP協(xié)議本身是無(wú)狀態(tài)的眨业,這與HTTP協(xié)議本來(lái)的目的是相符的急膀,客戶端只需要簡(jiǎn)單的向服務(wù)器請(qǐng)求下載某些文件,無(wú)論是客戶端還是服務(wù)器都沒(méi)有必要紀(jì)錄彼此過(guò)去的行為龄捡,每一次請(qǐng)求之間都是獨(dú)立的卓嫂,好比一個(gè)顧客和一個(gè)自動(dòng)售貨機(jī)或者一個(gè)普通的(非會(huì)員制)大賣場(chǎng)之間的關(guān)系一樣。

然而聰明(或者貪心聘殖?)的人們很快發(fā)現(xiàn)如果能夠提供一些按需生成的動(dòng)態(tài)信息會(huì)使web變得更加有用晨雳,就像給有線電視加上點(diǎn)播功能一樣行瑞。這種需求一方面迫使HTML逐步添加了表單、腳本餐禁、DOM等客戶端行為血久,另一方面在服務(wù)器端則出現(xiàn)了CGI規(guī)范以響應(yīng)客戶端的動(dòng)態(tài)請(qǐng)求,作為傳輸載體的HTTP協(xié)議也添加了文件上載帮非、cookie這些特性氧吐。其中cookie的作用就是為了解決HTTP協(xié)議無(wú)狀態(tài)的缺陷所作出的努力。至于后來(lái)出現(xiàn)的session機(jī)制則是又一種在客戶端與服務(wù)器之間保持狀態(tài)的解決方案末盔。

讓我們用幾個(gè)例子來(lái)描述一下cookie和session機(jī)制之間的區(qū)別與聯(lián)系筑舅。筆者曾經(jīng)常去的一家咖啡店有喝5杯咖啡免費(fèi)贈(zèng)一杯咖啡的優(yōu)惠,然而一次性消費(fèi)5杯咖啡的機(jī)會(huì)微乎其微陨舱,這時(shí)就需要某種方式來(lái)紀(jì)錄某位顧客的消費(fèi)數(shù)量豁翎。想象一下其實(shí)也無(wú)外乎下面的幾種方案:
1、該店的店員很厲害隅忿,能記住每位顧客的消費(fèi)數(shù)量心剥,只要顧客一走進(jìn)咖啡店,店員就知道該怎么對(duì)待了背桐。這種做法就是協(xié)議本身支持狀態(tài)优烧。
2、發(fā)給顧客一張卡片链峭,上面記錄著消費(fèi)的數(shù)量畦娄,一般還有個(gè)有效期限。每次消費(fèi)時(shí)弊仪,如果顧客出示這張卡片熙卡,則此次消費(fèi)就會(huì)與以前或以后的消費(fèi)相聯(lián)系起來(lái)。這種做法就是在客戶端保持狀態(tài)励饵。
3驳癌、發(fā)給顧客一張會(huì)員卡,除了卡號(hào)之外什么信息也不紀(jì)錄役听,每次消費(fèi)時(shí)颓鲜,如果顧客出示該卡片,則店員在店里的紀(jì)錄本上找到這個(gè)卡號(hào)對(duì)應(yīng)的紀(jì)錄添加一些消費(fèi)信息典予。這種做法就是在服務(wù)器端保持狀態(tài)甜滨。

由于HTTP協(xié)議是無(wú)狀態(tài)的,而出于種種考慮也不希望使之成為有狀態(tài)的瘤袖,因此衣摩,后面兩種方案就成為現(xiàn)實(shí)的選擇。具體來(lái)說(shuō)cookie機(jī)制采用的是在客戶端保持狀態(tài)的方案捂敌,而session機(jī)制采用的是在服務(wù)器端保持狀態(tài)的方案艾扮。同時(shí)我們也看到既琴,由于采用服務(wù)器端保持狀態(tài)的方案在客戶端也需要保存一個(gè)標(biāo)識(shí),所以session機(jī)制可能需要借助于cookie機(jī)制來(lái)達(dá)到保存標(biāo)識(shí)的目的栏渺,但實(shí)際上它還有其他選擇。

三锐涯、理解cookie機(jī)制
cookie機(jī)制的基本原理就如上面的例子一樣簡(jiǎn)單磕诊,但是還有幾個(gè)問(wèn)題需要解決:“會(huì)員卡”如何分發(fā);“會(huì)員卡”的內(nèi)容纹腌;以及客戶如何使用“會(huì)員卡”霎终。

正統(tǒng)的cookie分發(fā)是通過(guò)擴(kuò)展HTTP協(xié)議來(lái)實(shí)現(xiàn)的,服務(wù)器通過(guò)在HTTP的響應(yīng)頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應(yīng)的cookie升薯。然而純粹的客戶端腳本如JavaScript或者VBScript也可以生成cookie莱褒。

而cookie的使用是由瀏覽器按照一定的原則在后臺(tái)自動(dòng)發(fā)送給服務(wù)器的。瀏覽器檢查所有存儲(chǔ)的cookie涎劈,如果某個(gè)cookie所聲明的作用范圍大于等于將要請(qǐng)求的資源所在的位置广凸,則把該cookie附在請(qǐng)求資源的HTTP請(qǐng)求頭上發(fā)送給服務(wù)器。意思是麥當(dāng)勞的會(huì)員卡只能在麥當(dāng)勞的店里出示蛛枚,如果某家分店還發(fā)行了自己的會(huì)員卡谅海,那么進(jìn)這家店的時(shí)候除了要出示麥當(dāng)勞的會(huì)員卡,還要出示這家店的會(huì)員卡蹦浦。

cookie的內(nèi)容主要包括:名字扭吁,值,過(guò)期時(shí)間盲镶,路徑和域侥袜。
其中域可以指定某一個(gè)域比如.google.com,相當(dāng)于總店招牌溉贿,比如寶潔公司枫吧,也可以指定一個(gè)域下的具體某臺(tái)機(jī)器比如www.google.com或者froogle.google.com,可以用飄柔來(lái)做比宇色。
路徑就是跟在域名后面的URL路徑由蘑,比如/或者/foo等等,可以用某飄柔專柜做比代兵。
路徑與域合在一起就構(gòu)成了cookie的作用范圍尼酿。
如果不設(shè)置過(guò)期時(shí)間,則表示這個(gè)cookie的生命期為瀏覽器會(huì)話期間植影,只要關(guān)閉瀏覽器窗口裳擎,cookie就消失了。這種生命期為瀏覽器會(huì)話期的cookie被稱為會(huì)話cookie思币。會(huì)話cookie一般不存儲(chǔ)在硬盤上而是保存在內(nèi)存里鹿响,當(dāng)然這種行為并不是規(guī)范規(guī)定的羡微。如果設(shè)置了過(guò)期時(shí)間,瀏覽器就會(huì)把cookie保存到硬盤上惶我,關(guān)閉后再次打開(kāi)瀏覽器妈倔,這些cookie仍然有效直到超過(guò)設(shè)定的過(guò)期時(shí)間。

存儲(chǔ)在硬盤上的cookie可以在不同的瀏覽器進(jìn)程間共享绸贡,比如兩個(gè)IE窗口盯蝴。而對(duì)于保存在內(nèi)存里的cookie,不同的瀏覽器有不同的處理方式听怕。對(duì)于IE捧挺,在一個(gè)打開(kāi)的窗口上按Ctrl-N(或者從文件菜單)打開(kāi)的窗口可以與原窗口共享,而使用其他方式新開(kāi)的IE進(jìn)程則不能共享已經(jīng)打開(kāi)的窗口的內(nèi)存cookie尿瞭;對(duì)于Mozilla Firefox0.8闽烙,所有的進(jìn)程和標(biāo)簽頁(yè)都可以共享同樣的cookie。一般來(lái)說(shuō)是用javascript的window.open打開(kāi)的窗口會(huì)與原窗口共享內(nèi)存cookie声搁。瀏覽器對(duì)于會(huì)話cookie的這種只認(rèn)cookie不認(rèn)人的處理方式經(jīng)常給采用session機(jī)制的web應(yīng)用程序開(kāi)發(fā)者造成很大的困擾黑竞。

下面就是一個(gè)goolge設(shè)置cookie的響應(yīng)頭的例子
HTTP/1.1 302 Found
Location: http://www.google.com/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html

這是使用HTTPLook這個(gè)HTTP Sniffer軟件來(lái)俘獲的HTTP通訊紀(jì)錄的一部分

瀏覽器在再次訪問(wèn)goolge的資源時(shí)自動(dòng)向外發(fā)送cookie

使用Firefox可以很容易的觀察現(xiàn)有的cookie的值
使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。

IE也可以設(shè)置在接受cookie前詢問(wèn)

這是一個(gè)詢問(wèn)接受cookie的對(duì)話框疏旨。

四摊溶、理解session機(jī)制
session機(jī)制是一種服務(wù)器端的機(jī)制,服務(wù)器使用一種類似于散列表的結(jié)構(gòu)(也可能就是使用散列表)來(lái)保存信息充石。

當(dāng)程序需要為某個(gè)客戶端的請(qǐng)求創(chuàng)建一個(gè)session的時(shí)候莫换,服務(wù)器首先檢查這個(gè)客戶端的請(qǐng)求里是否已包含了一個(gè)session標(biāo)識(shí)- 稱為session id,如果已包含一個(gè)session id則說(shuō)明以前已經(jīng)為此客戶端創(chuàng)建過(guò)session骤铃,服務(wù)器就按照session id把這個(gè)session檢索出來(lái)使用(如果檢索不到拉岁,可能會(huì)新建一個(gè)),如果客戶端請(qǐng)求不包含session id惰爬,則為此客戶端創(chuàng)建一個(gè)session并且生成一個(gè)與此session相關(guān)聯(lián)的session id喊暖,session id的值應(yīng)該是一個(gè)既不會(huì)重復(fù),又不容易被找到規(guī)律以仿造的字符串撕瞧,這個(gè)session id將被在本次響應(yīng)中返回給客戶端保存陵叽。 保存這個(gè)session id的方式可以采用cookie,這樣在交互過(guò)程中瀏覽器可以自動(dòng)的按照規(guī)則把這個(gè)標(biāo)識(shí)發(fā)揮給服務(wù)器丛版。一般這個(gè)cookie的名字都是類似于SEEESIONID巩掺,而。比如weblogic對(duì)于web應(yīng)用程序生成的cookie页畦,JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764胖替,它的名字就是JSESSIONID。

由于cookie可以被人為的禁止,必須有其他機(jī)制以便在cookie被禁止時(shí)仍然能夠把session id傳遞回服務(wù)器独令。經(jīng)常被使用的一種技術(shù)叫做URL重寫端朵,就是把session id直接附加在URL路徑的后面,附加方式也有兩種燃箭,一種是作為URL路徑的附加信息冲呢,表現(xiàn)形式為http://...../xxx;jsessionid=ByOK ... 99zWpBng!-145788764
另一種是作為查詢字符串附加在URL后面,表現(xiàn)形式為http://...../xxx?jsessionid=ByOK ... 99zWpBng!-145788764
這兩種方式對(duì)于用戶來(lái)說(shuō)是沒(méi)有區(qū)別的招狸,只是服務(wù)器在解析的時(shí)候處理的方式不同敬拓,采用第一種方式也有利于把session id的信息和正常程序參數(shù)區(qū)分開(kāi)來(lái)。
為了在整個(gè)交互過(guò)程中始終保持狀態(tài)瓢颅,就必須在每個(gè)客戶端可能請(qǐng)求的路徑后面都包含這個(gè)session id恩尾。

另一種技術(shù)叫做表單隱藏字段弛说。就是服務(wù)器會(huì)自動(dòng)修改表單挽懦,添加一個(gè)隱藏字段,以便在表單提交時(shí)能夠把session id傳遞回服務(wù)器木人。比如下面的表單

在被傳遞給客戶端之前將被改寫成

這種技術(shù)現(xiàn)在已較少應(yīng)用信柿,筆者接觸過(guò)的很古老的iPlanet6(SunONE應(yīng)用服務(wù)器的前身)就使用了這種技術(shù)。
實(shí)際上這種技術(shù)可以簡(jiǎn)單的用對(duì)action應(yīng)用URL重寫來(lái)代替醒第。

在談?wù)搒ession機(jī)制的時(shí)候渔嚷,常常聽(tīng)到這樣一種誤解“只要關(guān)閉瀏覽器,session就消失了”稠曼。其實(shí)可以想象一下會(huì)員卡的例子形病,除非顧客主動(dòng)對(duì)店家提出銷卡,否則店家絕對(duì)不會(huì)輕易刪除顧客的資料霞幅。對(duì)session來(lái)說(shuō)也是一樣的漠吻,除非程序通知服務(wù)器刪除一個(gè)session,否則服務(wù)器會(huì)一直保留司恳,程序一般都是在用戶做log off的時(shí)候發(fā)個(gè)指令去刪除session途乃。然而瀏覽器從來(lái)不會(huì)主動(dòng)在關(guān)閉之前通知服務(wù)器它將要關(guān)閉,因此服務(wù)器根本不會(huì)有機(jī)會(huì)知道瀏覽器已經(jīng)關(guān)閉扔傅,之所以會(huì)有這種錯(cuò)覺(jué)耍共,是大部分session機(jī)制都使用會(huì)話cookie來(lái)保存session id,而關(guān)閉瀏覽器后這個(gè)session id就消失了猎塞,再次連接服務(wù)器時(shí)也就無(wú)法找到原來(lái)的session试读。如果服務(wù)器設(shè)置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發(fā)出的HTTP請(qǐng)求頭荠耽,把原來(lái)的session id發(fā)送給服務(wù)器鹏往,則再次打開(kāi)瀏覽器仍然能夠找到原來(lái)的session。

恰恰是由于關(guān)閉瀏覽器不會(huì)導(dǎo)致session被刪除,迫使服務(wù)器為seesion設(shè)置了一個(gè)失效時(shí)間伊履,當(dāng)距離客戶端上一次使用session的時(shí)間超過(guò)這個(gè)失效時(shí)間時(shí)韩容,服務(wù)器就可以認(rèn)為客戶端已經(jīng)停止了活動(dòng),才會(huì)把session刪除以節(jié)省存儲(chǔ)空間唐瀑。

五群凶、理解javax.servlet.http.HttpSession
HttpSession是Java平臺(tái)對(duì)session機(jī)制的實(shí)現(xiàn)規(guī)范,因?yàn)樗鼉H僅是個(gè)接口哄辣,具體到每個(gè)web應(yīng)用服務(wù)器的提供商请梢,除了對(duì)規(guī)范支持之外,仍然會(huì)有一些規(guī)范里沒(méi)有規(guī)定的細(xì)微差異力穗。這里我們以BEA的Weblogic Server8.1作為例子來(lái)演示毅弧。

首先,Weblogic Server提供了一系列的參數(shù)來(lái)控制它的HttpSession的實(shí)現(xiàn)当窗,包括使用cookie的開(kāi)關(guān)選項(xiàng)够坐,使用URL重寫的開(kāi)關(guān)選項(xiàng),session持久化的設(shè)置崖面,session失效時(shí)間的設(shè)置元咙,以及針對(duì)cookie的各種設(shè)置,比如設(shè)置cookie的名字巫员、路徑庶香、域,cookie的生存時(shí)間等简识。

一般情況下赶掖,session都是存儲(chǔ)在內(nèi)存里,當(dāng)服務(wù)器進(jìn)程被停止或者重啟的時(shí)候七扰,內(nèi)存里的session也會(huì)被清空奢赂,如果設(shè)置了session的持久化特性头遭,服務(wù)器就會(huì)把session保存到硬盤上绰上,當(dāng)服務(wù)器進(jìn)程重新啟動(dòng)或這些信息將能夠被再次使用,Weblogic Server支持的持久性方式包括文件碘梢、數(shù)據(jù)庫(kù)疫鹊、客戶端cookie保存和復(fù)制袖瞻。

復(fù)制嚴(yán)格說(shuō)來(lái)不算持久化保存,因?yàn)閟ession實(shí)際上還是保存在內(nèi)存里拆吆,不過(guò)同樣的信息被復(fù)制到各個(gè)cluster內(nèi)的服務(wù)器進(jìn)程中聋迎,這樣即使某個(gè)服務(wù)器進(jìn)程停止工作也仍然可以從其他進(jìn)程中取得session。

cookie生存時(shí)間的設(shè)置則會(huì)影響瀏覽器生成的cookie是否是一個(gè)會(huì)話cookie枣耀。默認(rèn)是使用會(huì)話cookie霉晕。有興趣的可以用它來(lái)試驗(yàn)我們?cè)诘谒墓?jié)里提到的那個(gè)誤解。

cookie的路徑對(duì)于web應(yīng)用程序來(lái)說(shuō)是一個(gè)非常重要的選項(xiàng),Weblogic Server對(duì)這個(gè)選項(xiàng)的默認(rèn)處理方式使得它與其他服務(wù)器有明顯的區(qū)別牺堰。后面我們會(huì)專題討論拄轻。

關(guān)于session的設(shè)置參考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

六、HttpSession常見(jiàn)問(wèn)題
(在本小節(jié)中session的含義為⑤和⑥的混合)

1伟葫、session在何時(shí)被創(chuàng)建
一個(gè)常見(jiàn)的誤解是以為session在有客戶端訪問(wèn)時(shí)就被創(chuàng)建恨搓,然而事實(shí)是直到某server端程序調(diào)用HttpServletRequest.getSession(true)這樣的語(yǔ)句時(shí)才被創(chuàng)建,注意如果JSP沒(méi)有顯示的使用 關(guān)閉session筏养,則JSP文件在編譯成Servlet時(shí)將會(huì)自動(dòng)加上這樣一條語(yǔ)句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對(duì)象的來(lái)歷斧抱。

由于session會(huì)消耗內(nèi)存資源,因此渐溶,如果不打算使用session辉浦,應(yīng)該在所有的JSP中關(guān)閉它。

2茎辐、session何時(shí)被刪除
綜合前面的討論宪郊,session在下列情況下被刪除a.程序調(diào)用HttpSession.invalidate();或b.距離上一次收到客戶端發(fā)送的session id時(shí)間間隔超過(guò)了session的超時(shí)設(shè)置;或c.服務(wù)器進(jìn)程被停止(非持久session)

3、如何做到在瀏覽器關(guān)閉時(shí)刪除session
嚴(yán)格的講荔茬,做不到這一點(diǎn)废膘≈窈#可以做一點(diǎn)努力的辦法是在所有的客戶端頁(yè)面里使用javascript代碼window.oncolose來(lái)監(jiān)視瀏覽器的關(guān)閉動(dòng)作慕蔚,然后向服務(wù)器發(fā)送一個(gè)請(qǐng)求來(lái)刪除session。但是對(duì)于瀏覽器崩潰或者強(qiáng)行殺死進(jìn)程這些非常規(guī)手段仍然無(wú)能為力斋配。

4孔飒、有個(gè)HttpSessionListener是怎么回事
你可以創(chuàng)建這樣的listener去監(jiān)控session的創(chuàng)建和銷毀事件,使得在發(fā)生這樣的事件時(shí)你可以做一些相應(yīng)的工作艰争。注意是session的創(chuàng)建和銷毀動(dòng)作觸發(fā)listener坏瞄,而不是相反。類似的與HttpSession有關(guān)的listener還有HttpSessionBindingListener甩卓,HttpSessionActivationListener和HttpSessionAttributeListener鸠匀。

5、存放在session中的對(duì)象必須是可序列化的嗎
不是必需的逾柿。要求對(duì)象可序列化只是為了session能夠在集群中被復(fù)制或者能夠持久保存或者在必要時(shí)server能夠暫時(shí)把session交換出內(nèi)存缀棍。在Weblogic Server的session中放置一個(gè)不可序列化的對(duì)象在控制臺(tái)上會(huì)收到一個(gè)警告。我所用過(guò)的某個(gè)iPlanet版本如果session中有不可序列化的對(duì)象机错,在session銷毀時(shí)會(huì)有一個(gè)Exception爬范,很奇怪。

6弱匪、如何才能正確的應(yīng)付客戶端禁止cookie的可能性
對(duì)所有的URL使用URL重寫青瀑,包括超鏈接,form的action,和重定向的URL斥难,具體做法參見(jiàn)[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

7枝嘶、開(kāi)兩個(gè)瀏覽器窗口訪問(wèn)應(yīng)用程序會(huì)使用同一個(gè)session還是不同的session
參見(jiàn)第三小節(jié)對(duì)cookie的討論,對(duì)session來(lái)說(shuō)是只認(rèn)id不認(rèn)人哑诊,因此不同的瀏覽器躬络,不同的窗口打開(kāi)方式以及不同的cookie存儲(chǔ)方式都會(huì)對(duì)這個(gè)問(wèn)題的答案有影響。

8搭儒、如何防止用戶打開(kāi)兩個(gè)瀏覽器窗口操作導(dǎo)致的session混亂
這個(gè)問(wèn)題與防止表單多次提交是類似的穷当,可以通過(guò)設(shè)置客戶端的令牌來(lái)解決。就是在服務(wù)器每次生成一個(gè)不同的id返回給客戶端淹禾,同時(shí)保存在session里馁菜,客戶端提交表單時(shí)必須把這個(gè)id也返回服務(wù)器,程序首先比較返回的id與保存在session里的值是否一致铃岔,如果不一致則說(shuō)明本次操作已經(jīng)被提交過(guò)了汪疮。可以參看《J2EE核心模式》關(guān)于表示層模式的部分毁习。需要注意的是對(duì)于使用javascript window.open打開(kāi)的窗口智嚷,一般不設(shè)置這個(gè)id,或者使用單獨(dú)的id纺且,以防主窗口無(wú)法操作盏道,建議不要再window.open打開(kāi)的窗口里做修改操作,這樣就可以不用設(shè)置载碌。

9猜嘱、為什么在Weblogic Server中改變session的值后要重新調(diào)用一次session.setValue
做這個(gè)動(dòng)作主要是為了在集群環(huán)境中提示W(wǎng)eblogic Server session中的值發(fā)生了改變,需要向其他服務(wù)器進(jìn)程復(fù)制新的session值嫁艇。

10朗伶、為什么session不見(jiàn)了
排除session正常失效的因素之外,服務(wù)器本身的可能性應(yīng)該是微乎其微的步咪,雖然筆者在iPlanet6SP1加若干補(bǔ)丁的Solaris版本上倒也遇到過(guò)论皆;瀏覽器插件的可能性次之,筆者也遇到過(guò)3721插件造成的問(wèn)題猾漫;理論上防火墻或者代理服務(wù)器在cookie處理上也有可能會(huì)出現(xiàn)問(wèn)題点晴。
出現(xiàn)這一問(wèn)題的大部分原因都是程序的錯(cuò)誤,最常見(jiàn)的就是在一個(gè)應(yīng)用程序中去訪問(wèn)另外一個(gè)應(yīng)用程序静袖。我們?cè)谙乱还?jié)討論這個(gè)問(wèn)題觉鼻。

七、跨應(yīng)用程序的session共享

常常有這樣的情況队橙,一個(gè)大項(xiàng)目被分割成若干小項(xiàng)目開(kāi)發(fā)坠陈,為了能夠互不干擾萨惑,要求每個(gè)小項(xiàng)目作為一個(gè)單獨(dú)的web應(yīng)用程序開(kāi)發(fā),可是到了最后突然發(fā)現(xiàn)某幾個(gè)小項(xiàng)目之間需要共享一些信息仇矾,或者想使用session來(lái)實(shí)現(xiàn)SSO(single sign on)庸蔼,在session中保存login的用戶信息,最自然的要求是應(yīng)用程序間能夠訪問(wèn)彼此的session贮匕。

然而按照Servlet規(guī)范姐仅,session的作用范圍應(yīng)該僅僅限于當(dāng)前應(yīng)用程序下,不同的應(yīng)用程序之間是不能夠互相訪問(wèn)對(duì)方的session的刻盐。各個(gè)應(yīng)用服務(wù)器從實(shí)際效果上都遵守了這一規(guī)范掏膏,但是實(shí)現(xiàn)的細(xì)節(jié)卻可能各有不同,因此解決跨應(yīng)用程序session共享的方法也各不相同敦锌。

首先來(lái)看一下Tomcat是如何實(shí)現(xiàn)web應(yīng)用程序之間session的隔離的馒疹,從Tomcat設(shè)置的cookie路徑來(lái)看,它對(duì)不同的應(yīng)用程序設(shè)置的cookie路徑是不同的乙墙,這樣不同的應(yīng)用程序所用的session id是不同的颖变,因此即使在同一個(gè)瀏覽器窗口里訪問(wèn)不同的應(yīng)用程序,發(fā)送給服務(wù)器的session id也可以是不同的听想。

根據(jù)這個(gè)特性腥刹,我們可以推測(cè)Tomcat中session的內(nèi)存結(jié)構(gòu)大致如下。

筆者以前用過(guò)的iPlanet也采用的是同樣的方式汉买,估計(jì)SunONE與iPlanet之間不會(huì)有太大的差別衔峰。對(duì)于這種方式的服務(wù)器,解決的思路很簡(jiǎn)單录别,實(shí)際實(shí)行起來(lái)也不難朽色。要么讓所有的應(yīng)用程序共享一個(gè)session id邻吞,要么讓應(yīng)用程序能夠獲得其他應(yīng)用程序的session id组题。

iPlanet中有一種很簡(jiǎn)單的方法來(lái)實(shí)現(xiàn)共享一個(gè)session id,那就是把各個(gè)應(yīng)用程序的cookie路徑都設(shè)為/(實(shí)際上應(yīng)該是/NASApp抱冷,對(duì)于應(yīng)用程序來(lái)講它的作用相當(dāng)于根)崔列。

/NASApp

需要注意的是,操作共享的session應(yīng)該遵循一些編程約定旺遮,比如在session attribute名字的前面加上應(yīng)用程序的前綴赵讯,使得setAttribute("name", "neo")變成setAttribute("app1.name", "neo"),以防止命名空間沖突耿眉,導(dǎo)致互相覆蓋边翼。

在Tomcat中則沒(méi)有這么方便的選擇。在Tomcat版本3上鸣剪,我們還可以有一些手段來(lái)共享session组底。對(duì)于版本4以上的Tomcat丈积,目前筆者尚未發(fā)現(xiàn)簡(jiǎn)單的辦法。只能借助于第三方的力量债鸡,比如使用文件江滨、數(shù)據(jù)庫(kù)、JMS或者客戶端cookie厌均,URL參數(shù)或者隱藏字段等手段唬滑。

我們?cè)倏匆幌耊eblogic Server是如何處理session的。

從截屏畫面上可以看到Weblogic Server對(duì)所有的應(yīng)用程序設(shè)置的cookie的路徑都是/棺弊,這是不是意味著在Weblogic Server中默認(rèn)的就可以共享session了呢晶密?然而一個(gè)小實(shí)驗(yàn)即可證明即使不同的應(yīng)用程序使用的是同一個(gè)session,各個(gè)應(yīng)用程序仍然只能訪問(wèn)自己所設(shè)置的那些屬性模她。這說(shuō)明Weblogic Server中的session的內(nèi)存結(jié)構(gòu)可能如下

對(duì)于這樣一種結(jié)構(gòu)惹挟,在session機(jī)制本身上來(lái)解決session共享的問(wèn)題應(yīng)該是不可能的了。除了借助于第三方的力量缝驳,比如使用文件连锯、數(shù)據(jù)庫(kù)、JMS或者客戶端cookie用狱,URL參數(shù)或者隱藏字段等手段运怖,還有一種較為方便的做法,就是把一個(gè)應(yīng)用程序的session放到ServletContext 中夏伊,這樣另外一個(gè)應(yīng)用程序就可以從ServletContext中取得前一個(gè)應(yīng)用程序的引用摇展。示例代碼如下,

應(yīng)用程序A
context.setAttribute("appA", session);

應(yīng)用程序B
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");

值得注意的是這種用法不可移植溺忧,因?yàn)楦鶕?jù)ServletContext的JavaDoc咏连,應(yīng)用服務(wù)器可以處于安全的原因?qū)τ赾ontext.getContext("/appA");返回空值,以上做法在Weblogic Server 8.1中通過(guò)鲁森。

那么Weblogic Server為什么要把所有的應(yīng)用程序的cookie路徑都設(shè)為/呢祟滴?原來(lái)是為了SSO,凡是共享這個(gè)session的應(yīng)用程序都可以共享認(rèn)證的信息歌溉。一個(gè)簡(jiǎn)單的實(shí)驗(yàn)就可以證明這一點(diǎn)垄懂,修改首先登錄的那個(gè)應(yīng)用程序的描述符weblogic.xml,把cookie路徑修改為/appA訪問(wèn)另外一個(gè)應(yīng)用程序會(huì)重新要求登錄痛垛,即使是反過(guò)來(lái)草慧,先訪問(wèn)cookie路徑為/的應(yīng)用程序,再訪問(wèn)修改過(guò)路徑的這個(gè)匙头,雖然不再提示登錄漫谷,但是登錄的用戶信息也會(huì)丟失。注意做這個(gè)實(shí)驗(yàn)時(shí)認(rèn)證方式應(yīng)該使用FORM蹂析,因?yàn)闉g覽器和web服務(wù)器對(duì)basic認(rèn)證方式有其他的處理方式舔示,第二次請(qǐng)求的認(rèn)證不是通過(guò)session來(lái)實(shí)現(xiàn)的朽寞。具體請(qǐng)參看[7] secion 14.8 Authorization,你可以修改所附的示例程序來(lái)做這些試驗(yàn)斩郎。

八脑融、總結(jié)
session機(jī)制本身并不復(fù)雜,然而其實(shí)現(xiàn)和配置上的靈活性卻使得具體情況復(fù)雜多變缩宜。這也要求我們不能把僅僅某一次的經(jīng)驗(yàn)或者某一個(gè)瀏覽器肘迎,服務(wù)器的經(jīng)驗(yàn)當(dāng)作普遍適用的經(jīng)驗(yàn),而是始終需要具體情況具體分析锻煌。

session與cookie區(qū)別

Session是由應(yīng)用服務(wù)器維持的一個(gè)服務(wù)器端的存儲(chǔ)空間妓布,用戶在連接服務(wù)器時(shí),會(huì)由服務(wù)器生成一個(gè)唯一的SessionID,用該SessionID為標(biāo)識(shí)符來(lái)存取服務(wù)器端的Session存儲(chǔ)空間宋梧。而SessionID這一數(shù)據(jù)則是保存到客戶端匣沼,用Cookie保存的,用戶提交頁(yè)面時(shí)捂龄,會(huì)將這一SessionID提交到服務(wù)器端释涛,來(lái)存取Session數(shù)據(jù)。這一過(guò)程倦沧,是不用開(kāi)發(fā)人員干預(yù)的唇撬。所以一旦客戶端禁用Cookie,那么Session也會(huì)失效展融。

服務(wù)器也可以通過(guò)URL重寫的方式來(lái)傳遞SessionID的值窖认,因此不是完全依賴Cookie。如果客戶端Cookie禁用告希,則服務(wù)器可以自動(dòng)通過(guò)重寫URL的方式來(lái)保存Session的值扑浸,并且這個(gè)過(guò)程對(duì)程序員透明。

可以試一下燕偶,即使不寫Cookie喝噪,在使用request.getCookies();取出的Cookie數(shù)組的長(zhǎng)度也是1,而這個(gè)Cookie的名字就是JSESSIONID杭跪,還有一個(gè)很長(zhǎng)的二進(jìn)制的字符串仙逻,是SessionID的值。

Cookie是客戶端的存儲(chǔ)空間涧尿,由瀏覽器來(lái)維持。

在一些投票之類的場(chǎng)合檬贰,我們往往因?yàn)楣降脑瓌t要求每人只能投一票姑廉,在一些WEB開(kāi)發(fā)中也有類似的情況,這時(shí)候我們通常會(huì)使用COOKIE來(lái)實(shí)現(xiàn)翁涤,例如如下的代碼:

< % cookie[]cookies = request.getCookies();

if (cookies.lenght == 0 || cookies == null)

doStuffForNewbie();

//沒(méi)有訪問(wèn)過(guò) www.2cto.com

}

else

{

doStuffForReturnVisitor(); //已經(jīng)訪問(wèn)過(guò)了

}

% >

這是很淺顯易懂的道理桥言,檢測(cè)COOKIE的存在萌踱,如果存在說(shuō)明已經(jīng)運(yùn)行過(guò)寫入COOKIE的代碼了,然而運(yùn)行以上的代碼后号阿,無(wú)論何時(shí)結(jié)果都是執(zhí)行doStuffForReturnVisitor()并鸵,通過(guò)控制面板-Internet選項(xiàng)-設(shè)置-察看文件卻始終看不到生成的cookie文件,奇怪扔涧,代碼明明沒(méi)有問(wèn)題园担,不過(guò)既然有cookie,那就顯示出來(lái)看看枯夜。

cookie[]cookies = request.getCookies();

if (cookies.lenght == 0 || cookies == null)

out.println("Has not visited this website");

}

else

{

for (int i = 0; i < cookie.length; i++)

{

out.println("cookie name:" + cookies[ i ].getName() + "cookie value:" +

cookie[ i ].getValue());

}

}

運(yùn)行結(jié)果:

cookie name:JSESSIONID cookie value:KWJHUG6JJM65HS2K6

為什么會(huì)有cookie呢,大家都知道弯汰,http是無(wú)狀態(tài)的協(xié)議,客戶每次讀取web頁(yè)面時(shí)湖雹,服務(wù)器都打開(kāi)新的會(huì)話咏闪,而且服務(wù)器也不會(huì)自動(dòng)維護(hù)客戶的上下文信息,那么要怎么才能實(shí)現(xiàn)網(wǎng)上商店中的購(gòu)物車呢摔吏,session就是一種保存上下文信息的機(jī)制鸽嫂,它是針對(duì)每一個(gè)用戶的,變量的值保存在服務(wù)器端征讲,通過(guò)SessionID來(lái)區(qū)分不同的客戶,session是以cookie或URL重寫為基礎(chǔ)的溪胶,默認(rèn)使用cookie來(lái)實(shí)現(xiàn),系統(tǒng)會(huì)創(chuàng)造一個(gè)名為JSESSIONID的輸出cookie稳诚,我們叫做session cookie,以區(qū)別persistentcookies,也就是我們通常所說(shuō)的cookie,注意sessioncookie是存儲(chǔ)于瀏覽器內(nèi)存中的哗脖,并不是寫到硬盤上的,這也就是我們剛才看到的JSESSIONID扳还。

我們通常情是看不到JSESSIONID的才避,但是當(dāng)我們把瀏覽器的cookie禁止后,web服務(wù)器會(huì)采用URL重寫的方式傳遞Sessionid氨距,我們就可以在地址欄看到sessionid=KWJHUG6JJM65HS2K6之類的字符串桑逝。

明白了原理,我們就可以很容易的分辨出persistent cookies和sessioncookie的區(qū)別了俏让,網(wǎng)上那些關(guān)于兩者安全性的討論也就一目了然了楞遏,session cookie針對(duì)某一次會(huì)話而言,會(huì)話結(jié)束sessioncookie也就隨著消失了首昔,而persistentcookie只是存在于客戶端硬盤上的一段文本(通常是加密的)寡喝,而且可能會(huì)遭到cookie欺騙以及針對(duì)cookie的跨站腳本攻擊,自然不如session cookie安全了勒奇。

通常sessioncookie是不能跨窗口使用的预鬓,當(dāng)你新開(kāi)了一個(gè)瀏覽器窗口進(jìn)入相同頁(yè)面時(shí),系統(tǒng)會(huì)賦予你一個(gè)新的sessionid赊颠,這樣我們信息共享的目的就達(dá)不到了格二,此時(shí)我們可以先把sessionid保存在persistentcookie中劈彪,然后在新窗口中讀出來(lái),就可以得到上一個(gè)窗口SessionID了顶猜,這樣通過(guò)session cookie和persistentcookie的結(jié)合我們就實(shí)現(xiàn)了跨窗口的session tracking(會(huì)話跟蹤)沧奴。

在一些web開(kāi)發(fā)的書(shū)中,往往只是簡(jiǎn)單的把Session和cookie作為兩種并列的http傳送信息的方式长窄,sessioncookies位于服務(wù)器端滔吠,persistentcookie位于客戶端,可是session又是以cookie為基礎(chǔ)的抄淑,明白的兩者之間的聯(lián)系和區(qū)別屠凶,我們就不難選擇合適的技術(shù)來(lái)開(kāi)發(fā)webservice了、
本文來(lái)自CSDN博客肆资,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/taoff/articles/1921009.aspx

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矗愧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子郑原,更是在濱河造成了極大的恐慌唉韭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件犯犁,死亡現(xiàn)場(chǎng)離奇詭異属愤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)酸役,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門住诸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人涣澡,你說(shuō)我怎么就攤上這事贱呐。” “怎么了入桂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵奄薇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我抗愁,道長(zhǎng)馁蒂,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任蜘腌,我火速辦了婚禮沫屡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逢捺。我一直安慰自己谁鳍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布劫瞳。 她就那樣靜靜地躺著倘潜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪志于。 梳的紋絲不亂的頭發(fā)上涮因,一...
    開(kāi)封第一講書(shū)人閱讀 48,954評(píng)論 1 283
  • 那天,我揣著相機(jī)與錄音伺绽,去河邊找鬼养泡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛奈应,可吹牛的內(nèi)容都是我干的澜掩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼杖挣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肩榕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起惩妇,我...
    開(kāi)封第一講書(shū)人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤株汉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后歌殃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體乔妈,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年氓皱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了路召。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡波材,死狀恐怖股淡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情各聘,我是刑警寧澤揣非,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站躲因,受9級(jí)特大地震影響早敬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜大脉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一搞监、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镰矿,春花似錦琐驴、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宙刘。三九已至,卻和暖如春牢酵,著一層夾襖步出監(jiān)牢的瞬間悬包,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工馍乙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留布近,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓丝格,卻偏偏與公主長(zhǎng)得像撑瞧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子显蝌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容