雖然session機制在web應(yīng)用程序中被采用已經(jīng)很長時間了茴肥,但是仍然有很多人不清楚session機制的本質(zhì)村生,以至不能正確的應(yīng)用這一技術(shù)洒宝。本文將詳細討論session的工作機制并且對在Java web application中應(yīng)用session機制時常見的問題作出解答蝇闭。
?一罕偎、術(shù)語session
在我的經(jīng)驗里,session這個詞被濫用的程度大概僅次于transaction陌知,更加有趣的是transaction與session在某些語境下的含義是相同的他托。
session,中文經(jīng)常翻譯為會話仆葡,其本來的含義是指有始有終的一系列動作/消息赏参,比如打電話時從拿起電話撥號到掛斷電話這中間的一系列過程可以稱之為一個session。有時候我們可以看到這樣的話“在一個瀏覽器會話期間沿盅,...”把篓,這里的會話一詞用的就是其本義,是指從一個瀏覽器窗口打開到關(guān)閉這個期間①腰涧。最混亂的是“用戶(客戶端)在一次會話期間”這樣一句話韧掩,它可能指用戶的一系列動作(一般情況下是同某個具體目的相關(guān)的一系列動作,比如從登錄到選購商品到結(jié)賬登出這樣一個網(wǎng)上購物的過程南窗,有時候也被稱為一個transaction)揍很,然而有時候也可能僅僅是指一次連接,也有可能是指含義①万伤,其中的差別只能靠上下文來推斷②窒悔。
然而當session一詞與網(wǎng)絡(luò)協(xié)議相關(guān)聯(lián)時,它又往往隱含了“面向連接”和/或“保持狀態(tài)”這樣兩個含義敌买,“面向連接”指的是在通信雙方在通信之前要先建立一個通信的渠道简珠,比如打電話,直到對方接了電話通信才能開始虹钮,與此相對的是寫信聋庵,在你把信發(fā)出去的時候你并不能確認對方的地址是否正確,通信渠道不一定能建立芙粱,但對發(fā)信人來說祭玉,通信已經(jīng)開始了〈号希“保持狀態(tài)”則是指通信的一方能夠把一系列的消息關(guān)聯(lián)起來脱货,使得消息之間可以互相依賴,比如一個服務(wù)員能夠認出再次光臨的老顧客并且記得上次這個顧客還欠店里一塊錢律姨。這一類的例子有“一個TCP session”或者“一個POP3 session”③振峻。
而到了web服務(wù)器蓬勃發(fā)展的時代,session在web開發(fā)語境下的語義又有了新的擴展择份,它的含義是指一類用來在客戶端與服務(wù)器之間保持狀態(tài)的解決方案④扣孟。有時候session也用來指這種解決方案的存儲結(jié)構(gòu),如“把xxx保存在session里”⑤荣赶。由于各種用于web開發(fā)的語言在一定程度上都提供了對這種解決方案的支持凤价,所以在某種特定語言的語境下鸽斟,session也被用來指代該語言的解決方案,比如經(jīng)常把Java里提供的javax.servlet.http.HttpSession簡稱為session⑥料仗。
鑒于這種混亂已不可改變湾盗,本文中session一詞的運用也會根據(jù)上下文有不同的含義,請大家注意分辨立轧。
在本文中格粪,使用中文“瀏覽器會話期間”來表達含義①,使用“session機制”來表達含義④氛改,使用“session”表達含義⑤帐萎,使用具體的“HttpSession”來表達含義⑥
二、由于HTTP協(xié)議的無狀態(tài)而出現(xiàn)的Cookie與Session
HTTP協(xié)議本身是無狀態(tài)的胜卤,這與HTTP協(xié)議本來的目的是相符的疆导,客戶端只需要簡單的向服務(wù)器請求下載某些文件,無論是客戶端還是服務(wù)器都沒有必要紀錄彼此過去的行為葛躏,每一次請求之間都是獨立的澈段,這意味著每次客戶端檢索網(wǎng)頁時,客戶端打開一個單獨的連接到 Web 服務(wù)器舰攒,服務(wù)器會自動不保留之前客戶端請求的任何記錄败富。
然而人們很快發(fā)現(xiàn)如果能夠提供一些按需生成的動態(tài)信息會使web變得更加有用,就像給有線電視加上點播功能一樣摩窃。這種需求一方面迫使HTML逐步添加了表單兽叮、腳本、DOM等客戶端行為猾愿,另一方面在服務(wù)器端則出現(xiàn)了CGI規(guī)范以響應(yīng)客戶端的動態(tài)請求鹦聪,作為傳輸載體的HTTP協(xié)議也添加了文件上載、cookie這些特性蒂秘。其中cookie的作用就是為了解決HTTP協(xié)議無狀態(tài)的缺陷所作出的努力泽本。至于后來出現(xiàn)的session機制則是又一種在客戶端與服務(wù)器之間保持狀態(tài)的解決方案。
具體來說cookie機制采用的是在客戶端保持狀態(tài)的方案姻僧,而session機制采用的是在服務(wù)器端保持狀態(tài)的方案观挎。同時我們也看到,由于采用服務(wù)器端保持狀態(tài)的方案在客戶端也需要保存一個標識段化,所以session機制可能需要借助于cookie機制來達到保存標識的目的,但實際上它還有其選擇造成。
三显熏、理解cookie機制
cookie機制的基本原理就如上面的例子一樣簡單,但是還有幾個問題需要解決:“會員卡”如何分發(fā)晒屎;“會員卡”的內(nèi)容喘蟆;以及客戶如何使用“會員卡”缓升。
正統(tǒng)的cookie分發(fā)是通過擴展HTTP協(xié)議來實現(xiàn)的,服務(wù)器通過在HTTP的響應(yīng)頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應(yīng)的cookie蕴轨。然而純粹的客戶端腳本如JavaScript或者VBScript也可以生成cookie港谊。
而cookie的使用是由瀏覽器按照一定的原則在后臺自動發(fā)送給服務(wù)器的。瀏覽器檢查所有存儲的cookie橙弱,如果某個cookie所聲明的作用范圍大于等于將要請求的資源所在的位置歧寺,則把該cookie附在請求資源的HTTP請求頭上發(fā)送給服務(wù)器。意思是麥當勞的會員卡只能在麥當勞的店里出示棘脐,如果某家分店還發(fā)行了自己的會員卡斜筐,那么進這家店的時候除了要出示麥當勞的會員卡,還要出示這家店的會員卡蛀缝。
cookie的內(nèi)容主要包括:名字顷链,值,過期時間屈梁,路徑和域嗤练。
其中域可以指定某一個域比如.google.com,相當于總店招牌在讶,比如寶潔公司煞抬,也可以指定一個域下的具體某臺機器比如www.google.com或者froogle.google.com,可以用飄柔來做比真朗。
路徑就是跟在域名后面的URL路徑此疹,比如/或者/foo等等,可以用某飄柔專柜做比遮婶。路徑與域合在一起就構(gòu)成了cookie的作用范圍蝗碎。如果不設(shè)置過期時間,則表示這個cookie的生命期為瀏覽器會話期間旗扑,只要關(guān)閉瀏覽器窗口蹦骑,cookie就消失了。這種生命期為瀏覽器會話期的cookie被稱為會話cookie臀防。會話cookie一般不存儲在硬盤上而是保存在內(nèi)存里眠菇,當然這種行為并不是規(guī)范規(guī)定的。如果設(shè)置了過期時間袱衷,瀏覽器就會把cookie保存到硬盤上捎废,關(guān)閉后再次打開瀏覽器,這些cookie仍然有效直到超過設(shè)定的過期時間致燥。
存儲在硬盤上的cookie可以在不同的瀏覽器進程間共享登疗,比如兩個IE窗口。而對于保存在內(nèi)存里的cookie,不同的瀏覽器有不同的處理方式辐益。對于IE断傲,在一個打開的窗口上按Ctrl-N(或者從文件菜單)打開的窗口可以與原窗口共享,而使用其他方式新開的IE進程則不能共享已經(jīng)打開的窗口的內(nèi)存cookie智政;對于Mozilla Firefox0.8认罩,所有的進程和標簽頁都可以共享同樣的cookie。一般來說是用javascript的window.open打開的窗口會與原窗口共享內(nèi)存cookie续捂。瀏覽器對于會話cookie的這種只認cookie不認人的處理方式經(jīng)常給采用session機制的web應(yīng)用程序開發(fā)者造成很大的困擾垦垂。
下面就是一個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這個HTTP Sniffer軟件來俘獲的HTTP通訊紀錄的一部分:
瀏覽器在再次訪問goolge的資源時自動向外發(fā)送cookie:
使用Firefox可以很容易的觀察現(xiàn)有的cookie的值,使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理疾忍。
IE也可以設(shè)置在接受cookie前詢問:
這是一個詢問接受cookie的對話框乔外。
四、理解JSP中的session機制
1一罩、JSP(java服務(wù)器頁面)
JSP全名為Java Server Pages杨幼,中文名叫java服務(wù)器頁面,其根本是一個簡化的Servlet設(shè)計聂渊,它是由Sun Microsystems公司倡導(dǎo)差购、許多公司參與一起建立的一種動態(tài)網(wǎng)頁技術(shù)標準。JSP技術(shù)有點類似ASP技術(shù)汉嗽,它是在傳統(tǒng)的網(wǎng)頁HTML(標準通用標記語言的子集)文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP標記(tag)欲逃,從而形成JSP文件,后綴名為(*.jsp)饼暑。 用JSP開發(fā)的Web應(yīng)用是跨平臺的稳析,既能在Linux下運行,也能在其他操作系統(tǒng)上運行弓叛。
它實現(xiàn)了Html語法中的java擴展(以 <%, %>形式)彰居。JSP與Servlet一樣,是在服務(wù)器端執(zhí)行的撰筷。通常返回給客戶端的就是一個HTML文本陈惰,因此客戶端只要有瀏覽器就能瀏覽。
JSP技術(shù)使用Java編程語言編寫類XML的tags和scriptlets毕籽,來封裝產(chǎn)生動態(tài)網(wǎng)頁的處理邏輯抬闯。網(wǎng)頁還能通過tags和scriptlets訪問存在于服務(wù)端的資源的應(yīng)用邏輯。JSP將網(wǎng)頁邏輯與網(wǎng)頁設(shè)計的顯示分離关筒,支持可重用的基于組件的設(shè)計溶握,使基于Web的應(yīng)用程序的開發(fā)變得迅速和容易。 JSP(JavaServer Pages)是一種動態(tài)頁面技術(shù)蒸播,它的主要目的是將表示邏輯從Servlet中分離出來睡榆。
Java Servlet是JSP的技術(shù)基礎(chǔ),而且大型的Web應(yīng)用程序的開發(fā)需要Java Servlet和JSP配合才能完成。JSP具備了Java技術(shù)的簡單易用肉微,完全的面向?qū)ο螅哂衅脚_無關(guān)性且安全可靠蜡塌,主要面向因特網(wǎng)的所有特點碉纳。
2、JSP中的session機制
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蜕劝,則為此客戶端創(chuàng)建一個session并且生成一個與此session相關(guān)聯(lián)的session id,session id的值應(yīng)該是一個既不會重復(fù)轰异,又不容易被找到規(guī)律以仿造的字符串存哲,這個session id將被在本次響應(yīng)中返回給客戶端保存春感。
在談?wù)搒ession機制的時候,常常聽到這樣一種誤解“只要關(guān)閉瀏覽器,session就消失了”饲化。其實對session來說,除非程序通知服務(wù)器刪除一個session焰情,否則服務(wù)器會一直保留闹司,程序一般都是在用戶做log off的時候發(fā)個指令去刪除session。然而瀏覽器從來不會主動在關(guān)閉之前通知服務(wù)器它將要關(guān)閉配椭,因此服務(wù)器根本不會有機會知道瀏覽器已經(jīng)關(guān)閉虫溜,之所以會有這種錯覺,是大部分session機制都使用會話cookie來保存session id颂郎,而關(guān)閉瀏覽器后這個session id就消失了吼渡,再次連接服務(wù)器時也就無法找到原來的session。如果服務(wù)器設(shè)置的cookie被保存到硬盤上乓序,或者使用某種手段改寫瀏覽器發(fā)出的HTTP請求頭寺酪,把原來的session id發(fā)送給服務(wù)器,則再次打開瀏覽器仍然能夠找到原來的session替劈。
恰恰是由于關(guān)閉瀏覽器不會導(dǎo)致session被刪除寄雀,迫使服務(wù)器為seesion設(shè)置了一個失效時間,當距離客戶端上一次使用session的時間超過這個失效時間時陨献,服務(wù)器就可以認為客戶端已經(jīng)停止了活動盒犹,才會把session刪除以節(jié)省存儲空間。
3、JSP中Session的實現(xiàn)方式
至今有以下三種方式來維持 Web 客戶端和 Web 服務(wù)器之間的 session 會話:
方式一:借助Cookies
保存session id的方式可以采用cookie急膀,這樣在交互過程中瀏覽器可以自動的按照規(guī)則把這個標識發(fā)揮給服務(wù)器沮协。一般這個cookie的名字都是類似于SEEESIONID,而卓嫂。比如weblogic對于web應(yīng)用程序生成的cookie慷暂,JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是JSESSIONID晨雳。
因為cookie可以被人為的禁止行瑞,所以這種借助Cookies來維持 session 會話的方式是有缺陷的。
方式二:URL 重寫
URL重寫就是把session id直接附加在URL路徑的后面餐禁,附加方式也有兩種血久,一種是作為URL路徑的附加信息,表現(xiàn)形式為http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
另一種是作為查詢字符串附加在URL后面帮非,表現(xiàn)形式為http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
這兩種方式對于用戶來說是沒有區(qū)別的氧吐,只是服務(wù)器在解析的時候處理的方式不同,采用第一種方式也有利于把session id的信息和正常程序參數(shù)區(qū)分開來喜鼓。
為了在整個交互過程中始終保持狀態(tài)副砍,就必須在每個客戶端可能請求的路徑后面都包含這個session id。
URL 重寫是一種更好的維持 session 會話的方式庄岖,它在瀏覽器不支持 cookie 時能夠很好地工作豁翎,但是它的缺點是會動態(tài)生成每個 URL 來為頁面分配一個 session 會話 ID,即使是在很簡單的靜態(tài) HTML 頁面中也會如此隅忿。
方式三:隱藏的表單字段
表單隱藏字段就是服務(wù)器會自動修改表單心剥,添加一個隱藏字段,以便在表單提交時能夠把session id傳遞回服務(wù)器背桐。如下所示:<input type="hidden" name="sessionid" value="12345">
該條目意味著优烧,當表單被提交時,指定的名稱和值會被自動包含在 GET 或 POST 數(shù)據(jù)中链峭。每次當 Web 瀏覽器發(fā)送回請求時畦娄,session_id 值可以用于保持不同的 Web 瀏覽器的跟蹤。這可能是一種保持 session 會話跟蹤的有效方式弊仪,但是點擊常規(guī)的超文本鏈接(<A HREF...>)不會導(dǎo)致表單提交熙卡,因此隱藏的表單字段也不支持常規(guī)的 session 會話跟蹤。這種技術(shù)現(xiàn)在已較少應(yīng)用励饵,實際上這種技術(shù)可以簡單的用對action應(yīng)用URL重寫來代替驳癌。
五、理解javax.servlet.http.HttpSession
HttpSession是Java平臺對session機制的實現(xiàn)規(guī)范役听,因為它僅僅是個接口颓鲜,具體到每個web應(yīng)用服務(wù)器的提供商表窘,除了對規(guī)范支持之外,仍然會有一些規(guī)范里沒有規(guī)定的細微差異甜滨。這里我們以BEA的Weblogic Server8.1作為例子來演示乐严。
首先,Weblogic Server提供了一系列的參數(shù)來控制它的HttpSession的實現(xiàn)衣摩,包括使用cookie的開關(guān)選項麦备,使用URL重寫的開關(guān)選項,session持久化的設(shè)置昭娩,session失效時間的設(shè)置,以及針對cookie的各種設(shè)置黍匾,比如設(shè)置cookie的名字栏渺、路徑、域锐涯,cookie的生存時間等磕诊。
一般情況下,session都是存儲在內(nèi)存里纹腌,當服務(wù)器進程被停止或者重啟的時候霎终,內(nèi)存里的session也會被清空,如果設(shè)置了session的持久化特性升薯,服務(wù)器就會把session保存到硬盤上莱褒,當服務(wù)器進程重新啟動或這些信息將能夠被再次使用,Weblogic Server支持的持久性方式包括文件涎劈、數(shù)據(jù)庫广凸、客戶端cookie保存和復(fù)制。
復(fù)制嚴格說來不算持久化保存蛛枚,因為session實際上還是保存在內(nèi)存里谅海,不過同樣的信息被復(fù)制到各個cluster內(nèi)的服務(wù)器進程中,這樣即使某個服務(wù)器進程停止工作也仍然可以從其他進程中取得session蹦浦。
cookie生存時間的設(shè)置則會影響瀏覽器生成的cookie是否是一個會話cookie扭吁。默認是使用會話cookie。有興趣的可以用它來試驗我們在第四節(jié)里提到的那個誤解盲镶。
cookie的路徑對于web應(yīng)用程序來說是一個非常重要的選項侥袜,Weblogic Server對這個選項的默認處理方式使得它與其他服務(wù)器有明顯的區(qū)別。
六徒河、JSP中的session對象
除了以上幾種方法外系馆,JSP利用servlet提供的HttpSession接口來識別一個用戶,存儲這個用戶的所有訪問信息顽照。
默認情況下由蘑,JSP允許會話跟蹤闽寡,一個新的HttpSession對象將會自動地為新的客戶端實例化。禁止會話跟蹤需要顯式地關(guān)掉它尼酿,通過將page指令中session屬性值設(shè)為false來實現(xiàn)爷狈,就像下面這樣:<%@ page session="false" %>
JSP引擎將隱含的session對象暴露給開發(fā)者。由于提供了session對象裳擎,開發(fā)者就可以方便地存儲或檢索數(shù)據(jù)涎永。
下表列出了session對象的一些重要方法:
1、public Object getAttribute(String name)
返回session對象中與指定名稱綁定的對象鹿响,如果不存在則返回null
2羡微、public Enumeration getAttributeNames()
返回session對象中所有的對象名稱
3、public long getCreationTime()
返回session對象被創(chuàng)建的時間惶我, 以毫秒為單位妈倔,從1970年1月1號凌晨開始算起
4、public String getId()
返回session對象的ID
5绸贡、public long getLastAccessedTime()
返回客戶端最后訪問的時間盯蝴,以毫秒為單位,從1970年1月1號凌晨開始算起
6听怕、public int getMaxInactiveInterval()
返回最大時間間隔捧挺,以秒為單位,servlet 容器將會在這段時間內(nèi)保持會話打開
7尿瞭、public void invalidate()
將session無效化闽烙,解綁任何與該session綁定的對象
8、public boolean isNew()
返回是否為一個新的客戶端声搁,或者客戶端是否拒絕加入session
9鸣峭、public void removeAttribute(String name)
移除session中指定名稱的對象
10、public void setAttribute(String name, Object value)?
使用指定的名稱和值來產(chǎn)生一個對象并綁定到session中
11酥艳、public void setMaxInactiveInterval(int interval)
用來指定時間摊溶,以秒為單位,servlet容器將會在這段時間內(nèi)保持會話有效
七充石、HttpSession常見問題(在本小節(jié)中session的含義為⑤和⑥的混合)
1莫换、session在何時被創(chuàng)建
?一個常見的誤解是以為session在有客戶端訪問時就被創(chuàng)建,然而事實是直到某server端程序調(diào)用HttpServletRequest.getSession(true)這樣的語句時才被創(chuàng)建骤铃,注意如果JSP沒有顯示的使用 <%@page session="false"%> 關(guān)閉session拉岁,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。
?由于session會消耗內(nèi)存資源惰爬,因此喊暖,如果不打算使用session,應(yīng)該在所有的JSP中關(guān)閉它撕瞧。
2陵叽、session何時被刪除
綜合前面的討論狞尔,session在下列情況下被刪除a.程序調(diào)用HttpSession.invalidate();或b.距離上一次收到客戶端發(fā)送的session id時間間隔超過了session的超時設(shè)置;或c.服務(wù)器進程被停止(非持久session)
3、如何做到在瀏覽器關(guān)閉時刪除session
嚴格的講巩掺,做不到這一點偏序。可以做一點努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監(jiān)視瀏覽器的關(guān)閉動作胖替,然后向服務(wù)器發(fā)送一個請求來刪除session研儒。但是對于瀏覽器崩潰或者強行殺死進程這些非常規(guī)手段仍然無能為力。
4独令、有個HttpSessionListener是怎么回事
你可以創(chuàng)建這樣的listener去監(jiān)控session的創(chuàng)建和銷毀事件端朵,使得在發(fā)生這樣的事件時你可以做一些相應(yīng)的工作。注意是session的創(chuàng)建和銷毀動作觸發(fā)listener燃箭,而不是相反逸月。類似的與HttpSession有關(guān)的listener還有HttpSessionBindingListener,HttpSessionActivationListener和HttpSessionAttributeListener遍膜。
5、存放在session中的對象必須是可序列化的嗎
不是必需的瓤湘。要求對象可序列化只是為了session能夠在集群中被復(fù)制或者能夠持久保存或者在必要時server能夠暫時把session交換出內(nèi)存瓢颅。在Weblogic Server的session中放置一個不可序列化的對象在控制臺上會收到一個警告。我所用過的某個iPlanet版本如果session中有不可序列化的對象弛说,在session銷毀時會有一個Exception挽懦,很奇怪。
6木人、如何才能正確的應(yīng)付客戶端禁止cookie的可能性
對所有的URL使用URL重寫信柿,包括超鏈接,form的action醒第,和重定向的URL渔嚷,具體做法參見[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770
7、開兩個瀏覽器窗口訪問應(yīng)用程序會使用同一個session還是不同的session
參見第三小節(jié)對cookie的討論稠曼,對session來說是只認id不認人形病,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲方式都會對這個問題的答案有影響霞幅。
8漠吻、如何防止用戶打開兩個瀏覽器窗口操作導(dǎo)致的session混亂
這個問題與防止表單多次提交是類似的,可以通過設(shè)置客戶端的令牌來解決司恳。就是在服務(wù)器每次生成一個不同的id返回給客戶端途乃,同時保存在session里,客戶端提交表單時必須把這個id也返回服務(wù)器扔傅,程序首先比較返回的id與保存在session里的值是否一致耍共,如果不一致則說明本次操作已經(jīng)被提交過了烫饼。可以參看《J2EE核心模式》關(guān)于表示層模式的部分划提。需要注意的是對于使用javascript window.open打開的窗口枫弟,一般不設(shè)置這個id,或者使用單獨的id鹏往,以防主窗口無法操作淡诗,建議不要再window.open打開的窗口里做修改操作,這樣就可以不用設(shè)置伊履。
9韩容、為什么在Weblogic Server中改變session的值后要重新調(diào)用一次session.setValue
做這個動作主要是為了在集群環(huán)境中提示W(wǎng)eblogic Server session中的值發(fā)生了改變,需要向其他服務(wù)器進程復(fù)制新的session值唐瀑。
10群凶、為什么session不見了
排除session正常失效的因素之外,服務(wù)器本身的可能性應(yīng)該是微乎其微的哄辣,雖然筆者在iPlanet6SP1加若干補丁的Solaris版本上倒也遇到過请梢;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題力穗;理論上防火墻或者代理服務(wù)器在cookie處理上也有可能會出現(xiàn)問題毅弧。
出現(xiàn)這一問題的大部分原因都是程序的錯誤,最常見的就是在一個應(yīng)用程序中去訪問另外一個應(yīng)用程序当窗。我們在下一節(jié)討論這個問題够坐。
八、跨應(yīng)用程序的session共享
常常有這樣的情況崖面,一個大項目被分割成若干小項目開發(fā)元咙,為了能夠互不干擾,要求每個小項目作為一個單獨的web應(yīng)用程序開發(fā)巫员,可是到了最后突然發(fā)現(xiàn)某幾個小項目之間需要共享一些信息庶香,或者想使用session來實現(xiàn)SSO(single sign on),在session中保存login的用戶信息简识,最自然的要求是應(yīng)用程序間能夠訪問彼此的session脉课。
然而按照Servlet規(guī)范,session的作用范圍應(yīng)該僅僅限于當前應(yīng)用程序下财异,不同的應(yīng)用程序之間是不能夠互相訪問對方的session的倘零。各個應(yīng)用服務(wù)器從實際效果上都遵守了這一規(guī)范,但是實現(xiàn)的細節(jié)卻可能各有不同戳寸,因此解決跨應(yīng)用程序session共享的方法也各不相同呈驶。
首先來看一下Tomcat是如何實現(xiàn)web應(yīng)用程序之間session的隔離的,從Tomcat設(shè)置的cookie路徑來看疫鹊,它對不同的應(yīng)用程序設(shè)置的cookie路徑是不同的袖瞻,這樣不同的應(yīng)用程序所用的session id是不同的司致,因此即使在同一個瀏覽器窗口里訪問不同的應(yīng)用程序,發(fā)送給服務(wù)器的session id也可以是不同的聋迎。對于這種方式的服務(wù)器脂矫,解決的思路很簡單,實際實行起來也不難霉晕。要么讓所有的應(yīng)用程序共享一個session id庭再,要么讓應(yīng)用程序能夠獲得其他應(yīng)用程序的session id。
我們再看一下Weblogic Server是如何處理session的牺堰,Weblogic Server對所有的應(yīng)用程序設(shè)置的cookie的路徑都是/拄轻,這是不是意味著在Weblogic Server中默認的就可以共享session了呢?然而一個小實驗即可證明即使不同的應(yīng)用程序使用的是同一個session伟葫,各個應(yīng)用程序仍然只能訪問自己所設(shè)置的那些屬性恨搓。這說明可能由于Weblogic Server中的session的內(nèi)存結(jié)構(gòu)原因,在session機制本身上來解決session共享的問題應(yīng)該是不可能的了筏养。除了借助于第三方的力量斧抱,比如使用文件、數(shù)據(jù)庫渐溶、JMS或者客戶端cookie辉浦,URL參數(shù)或者隱藏字段等手段,還有一種較為方便的做法掌猛,就是把一個應(yīng)用程序的session放到ServletContext中,這樣另外一個應(yīng)用程序就可以從ServletContext中取得前一個應(yīng)用程序的引用眉睹。值得注意的是這種用法不可移植荔茬,因為根據(jù)ServletContext的JavaDoc,應(yīng)用服務(wù)器可以處于安全的原因?qū)τ赾ontext.getContext("/appA");返回空值竹海,以上做法在Weblogic Server 8.1中通過慕蔚。那么Weblogic Server為什么要把所有的應(yīng)用程序的cookie路徑都設(shè)為/呢?原來是為了SSO斋配,凡是共享這個session的應(yīng)用程序都可以共享認證的信息孔飒。一個簡單的實驗就可以證明這一點,修改首先登錄的那個應(yīng)用程序的描述符weblogic.xml艰争,把cookie路徑修改為/appA訪問另外一個應(yīng)用程序會重新要求登錄坏瞄,即使是反過來,先訪問cookie路徑為/的應(yīng)用程序甩卓,再訪問修改過路徑的這個鸠匀,雖然不再提示登錄,但是登錄的用戶信息也會丟失逾柿。注意做這個實驗時認證方式應(yīng)該使用FORM缀棍,因為瀏覽器和web服務(wù)器對basic認證方式有其他的處理方式宅此,第二次請求的認證不是通過session來實現(xiàn)的。
九爬范、總結(jié)
session機制本身并不復(fù)雜父腕,然而其實現(xiàn)和配置上的靈活性卻使得具體情況復(fù)雜多變。這也要求我們不能把僅僅某一次的經(jīng)驗或者某一個瀏覽器青瀑、服務(wù)器的經(jīng)驗當作普遍適用的經(jīng)驗璧亮,而是始終需要具體情況具體分析。