Chinaorg

          于千萬(wàn)人之中,遇見你所遇見的人;于千萬(wàn)年之中,時(shí)間的無(wú)涯荒野里,沒有早一步,也沒有晚一步,剛巧趕上了
          我不去想是否能夠成功,既然選擇了遠(yuǎn)方,便只顧風(fēng)雨兼程; 我不去想,身后會(huì)不會(huì)襲來(lái)寒風(fēng)冷雨,既然目標(biāo)是地平線,留給世界的只能是背影
          posts - 20, comments - 6, trackbacks - 0, articles - 0

          jsp的session詳解 (下)

          Posted on 2006-10-24 19:52 chinaorg 閱讀(299) 評(píng)論(0)  編輯  收藏
          五、理解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ī)范里沒有規(guī)定的細(xì)微差異。這里我們以BEA的Weblogic?Server8.1作為例子來(lái)演示。

          首先,Weblogic?Server提供了一系列的參數(shù)來(lái)控制它的HttpSession的實(shí)現(xiàn),包括使用cookie的開關(guān)選項(xiàng),使用URL重寫的開關(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常見問(wèn)題
          (在本小節(jié)中session的含義為⑤和⑥的混合)


          1、session在何時(shí)被創(chuàng)建
          一個(gè)常見的誤解是以為session在有客戶端訪問(wèn)時(shí)就被創(chuàng)建,然而事實(shí)是直到某server端程序調(diào)用 HttpServletRequest.getSession(true)這樣的語(yǔ)句時(shí)才被創(chuàng)建,注意如果JSP沒有顯示的使用?<% @page?session="false"%>?關(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)??梢宰鲆稽c(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,具體做法參見[6]
          http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

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

          8、如何防止用戶打開兩個(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ò)了??梢詤⒖础禞2EE核心模式》關(guān)于表示層模式的部分。需要注意的是對(duì)于使用javascript?window.open打開的窗口,一般不設(shè)置這個(gè)id,或者使用單獨(dú)的id,以防主窗口無(wú)法操作,建議不要再window.open打開的窗口里做修改操作,這樣就可以不用設(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不見了
          排除session正常失效的因素之外,服務(wù)器本身的可能性應(yīng)該是微乎其微的,雖然筆者在iPlanet6SP1加若干補(bǔ)丁的Solaris版本上倒也遇到過(guò);瀏覽器插件的可能性次之,筆者也遇到過(guò)3721插件造成的問(wèn)題;理論上防火墻或者代理服務(wù)器在cookie處理上也有可能會(huì)出現(xiàn)問(wèn)題。
          出現(xiàn)這一問(wèn)題的大部分原因都是程序的錯(cuò)誤,最常見的就是在一個(gè)應(yīng)用程序中去訪問(wèn)另外一個(gè)應(yīng)用程序。我們?cè)谙乱还?jié)討論這個(gè)問(wèn)題。

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

          常常有這樣的情況,一個(gè)大項(xiàng)目被分割成若干小項(xiàng)目開發(fā),為了能夠互不干擾,要求每個(gè)小項(xiàng)目作為一個(gè)單獨(dú)的web應(yīng)用程序開發(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)于根)。
          <session-info>
          <path>/NASApp</path>
          </session-info>

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


          在Tomcat中則沒有這么方便的選擇。在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),而是始終需要具體情況具體分析。

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 西峡县| 佛学| 宣威市| 海兴县| 横峰县| 仁寿县| 祥云县| 八宿县| 泸溪县| 景洪市| 中牟县| 永新县| 运城市| 仪陇县| 襄城县| 丰原市| 元阳县| 汨罗市| 新余市| 普洱| 常德市| 阿拉尔市| 岳阳县| 马龙县| 永宁县| 锡林郭勒盟| 蒙自县| 紫阳县| 石景山区| 十堰市| 涟源市| 上思县| 兴山县| 邓州市| 青冈县| 绥芬河市| 友谊县| 高陵县| 仁怀市| 天等县| 武宁县|