Session那些事(一)

    

      前一段時間做一個應用的客戶端時,涉及到用戶權限的問題,所以用到了Session,遇到一些問題,網上找了各位大神的一些資料,今天彙總到這,以便以後複習。

 

1.Session

由於HTTP協議連接的無狀態性,才使得session的不得已而產生。既然Web應用並不瞭解有關同一用戶以前請求的信息,那麼解決這個問題的一個辦法是使用Servlet/JSP容器提供的會話跟蹤功能,Servlet API規範定義了一個簡單的HttpSession接口,通過它我們可以方便地實現會話跟蹤。

 HttpSession接口提供了存儲和返回標準會話屬性的方法。標準會話屬性如會話標識符、應用數據等,都以“名字-值”對的形式保存在服務器端。也就是說,HttpSession接口提供了一種把對象保存到內存、在同一用戶的後繼請求中提取這些對象的標準辦法。在會話中保存數據的方法是setAttribute(String s, Object o),從會話提取原來所保存對象的方法是getAttribute(String s)。

在服務器端,每當新用戶請求了一個使用HttpSession對象的JSP頁面,Servlet、JSP容器除了發回應答頁面外,它還要以cookie的形式向瀏覽器發送一個特殊數字,即“繪畫標識符”,它是一個唯一的用戶標示符,瀏覽器在請求session時,服務器會先得到它的sessionId,在做處理。
 會話標識符以Cookie的形式在服務器和瀏覽器組件傳送,標準會話屬性在服務器端也是以會話的形式存在,並且這個Cookie的生命週期只是臨時的,即會話結束後就自動消失,沒有爲它指定固定的生命週期,因此可以說session是基於Cookie的技術。另外,如果客戶端不支持Cookie,運用URL重寫機制來保證會話標識回服務器。


2.session機制的實現:

 
(1.)session機制是一種服務器端的機制,
用來在無狀態的HTTP協議下越過多個請求頁面來維持狀態和識別用戶。
當程序需要爲某個客戶端的請求創建一個session的時候,
服務器首先檢查這個客戶端的請求裏是否已包含了一個session標識。

這個標識稱爲session id,
如果已包含一個session id則說明以前已經爲此客戶端創建過session,
服務器就按照session id把這個session檢索出來使用,
若沒有創建過,則創建一個新的Session。

那麼這個session是什麼時候創建的呢?
之前一直錯誤地理解爲:
當用戶向服務器發起請求時,這個session便會立刻建立起來,
但實際上卻根本不是這樣。

在Servlet中,你肯定用過下面這句話,

HttpSession session = request.getSession();如果當前沒有session,則會立刻建立一個session;
如果有session則返回當前session。

這句話和

HttpSession session = request.getSession(true);的效果是一樣的。

但是如果你寫成

HttpSession session = request.getSession(false);則不會自動建立session。
若當前沒有session,你所得到的seesion只會是一個null。

總結:
session不是一打開網站就會立刻建立。
它的建立需要基於下面兩個條件中的任意一個:

   a:在servlet中手動調用

HttpSession session = request.getSession();或者

HttpSession session = request.getSession(true);2:jsp中沒有寫
(默認情況下它是的)

如果兩個條件同時都不滿足,那麼你建立的只是一個無seesion的連接。

 


(2.) session機制是一種服務器端的機制,服務器使用一種類似於散列表的結構(也可能就是使用散列表)來保存信息。
      當程序需要爲某個客戶端的請求創建一個session的時候,

第一步:
      服務器首先檢查這個客戶端的請求裏是否已包含了一個session標識 - 稱爲session id,
此時就是兩種可能,客戶機有session id或者沒有session id

第二步:
      如果已包含一個session id則說明以前已經爲此客戶端創建過session,服務器就按照session id把這個session檢索出來使用(如果檢索不到,可能會新建一個)
      如果客戶端請求不包含session id,則爲此客戶端創建一個session並且生成一個與此session相關聯的session id
(session id的值應該是一個既不會重複,又不容易被找到規律以仿造的字符串,這個session id將被在本次響應中返回給客戶端保存。)

三、保存session id 的方法
一)、cookie:
二)、URL重寫:
cookie可以被人爲的禁止,必須有其他機制以便在cookie被禁止時仍然能夠把session id傳遞迴服務器。經常被使用的一種技術叫做URL重寫,就是把session id直接附加在URL路徑

的後面。


3.session與Cookie的實現原理

Session 與 Cookie 的作用都是爲了保持訪問用戶與後端服務器的交互狀態。它們有各自的優點也有各自的缺陷。然而具有諷刺意味的是它們優點和它們的使用場景又是矛盾的,例如使用 Cookie 來傳遞信息時,隨着 Cookie 個數的增多和訪問量的增加,它佔用的網絡帶寬也很大,試想假如 Cookie 佔用 200 個字節,如果一天的 PV 有幾億的時候,它要佔用多少帶寬。所以大訪問量的時候希望用 Session,但是 Session 的致命弱點是不容易在多臺服務器之間共享,所以這也限制了 Session 的使用。

不管 Session 和 Cookie 有什麼不足,我們還是要用它們。下面詳細講一下,Session 如何基於 Cookie 來工作。實際上有三種方式能可以讓 Session 正常工作:

1.基於 URL Path Parameter,默認就支持
2.基於 Cookie,如果你沒有修改 Context 容器個 cookies 標識的話,默認也是支持的
3.基於 SSL,默認不支持,只有 connector.getAttribute("SSLEnabled") 爲 TRUE 時才支持
第一種情況下,當瀏覽器不支持 Cookie 功能時,瀏覽器會將用戶的 SessionCookieName 重寫到用戶請求的 URL 參數中,它的傳遞格式如 /path/Servlet;name=value;name2=value2? Name3=value3,其中“Servlet;”後面的 K-V 對就是要傳遞的 Path Parameters,服務器會從這個 Path Parameters 中拿到用戶配置的 SessionCookieName。關於這個 SessionCookieName,如果你在 web.xml 中配置 session-config 配置項的話,其 cookie-config 下的 name 屬性就是這個 SessionCookieName 值,如果你沒有配置 session-config 配置項,默認的 SessionCookieName 就是大家熟悉的“JSESSIONID”。接着 Request 根據這個 SessionCookieName 到 Parameters 拿到 Session ID 並設置到 request.setRequestedSessionId 中。

請注意如果客戶端也支持 Cookie 的話,Tomcat 仍然會解析 Cookie 中的 Session ID,並會覆蓋 URL 中的 Session ID。

如果是第三種情況的話將會根據 javax.servlet.request.ssl_session 屬性值設置 Session ID。

有了 Session ID 服務器端就可以創建 HttpSession 對象了,第一次觸發是通過 request. getSession() 方法,如果當前的 Session ID 還沒有對應的 HttpSession 對象那麼就創

建一個新的,並將這個對象加到 org.apache.catalina. Manager 的 sessions 容器中保存,Manager 類將管理所有 Session 的生命週期,Session 過期將被回收,服務器關閉,

Session 將被序列化到磁盤等。只要這個 HttpSession 對象存在,用戶就可以根據 Session ID 來獲取到這個對象,也就達到了狀態的保持。

 

還有一點與 Session 關聯的 Cookie 與其它 Cookie 沒有什麼不同,這個配置的配置可以通過 web.xml 中的 session-config 配置項來指定。


4.session中的一些問題
    (1)、session在何時被創建

  一個常見的誤解是以爲session在有客戶端訪問時就被創建,然而事實是直到某server端程序調用 HttpServletRequest.getSession(true)這樣的語句時才被創建,注意如果JSP沒有顯示的使用 <%@page session="false"%> 關閉session,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。

  由於session會消耗內存資源,因此,如果不打算使用session,應該在所有的JSP中關閉它。

 (2)、session何時被刪除

  綜合前面的討論,session在下列情況下被刪除a.程序調用HttpSession.invalidate();或b.距離上一次收到客戶端發送的session id時間間隔超過了session的超時設置;或c.服務器進程被停止(非持久session)

 (3)、如何做到在瀏覽器關閉時刪除session

  嚴格的講,做不到這一點。可以做一點努力的辦法是在所有的客戶端頁面裏使用網頁特效代碼window.onclose來監視瀏覽器的關閉 動作,然後向服務器發送一個請求來刪

除session。但是對於瀏覽器崩潰或者強行殺死進程這些非常規手段仍然無能爲力。

 (4)、有個HttpSessionListener是怎麼回事

  你可以創建這樣的listener去監控session的創建和銷燬事件,使得在發生這樣的事件時你可以做一些相應的工作。注意是 session的創建和銷燬動作觸發listener,而不是相反。類似的與HttpSession有關的listener還有 HttpSessionBindingListener,HttpSessionActivationListener和 HttpSessionAttributeListener。

 (5)、存放在session中的對象必須是可序列化的嗎

  不是必需的。要求對象可序列化只是爲了session能夠在集羣中被複制或者能夠持久保存或者在必要時server能夠暫時把session交換出內 存。在Weblogic Server的session中放置一個不可序列化的對象在控制檯上會收到一個警告。我所用過的某個iPlanet版本如果session中有不可序列化 的對象,在session銷燬時會有一個Exception,很奇怪。

 (6.)、如何才能正確的應付客戶端禁止cookie的可能性

  對所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見[6]http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

 (7.)、開兩個瀏覽器窗口訪問應用程序會使用同一個session還是不同的session

  參見第三小節對cookie的討論,對session來說是隻認id不認人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲方式都會對這個問題的答案有影響。

    (8.)、如何防止用戶打開兩個瀏覽器窗口操作導致的session混亂

  這個問題與防止表單多次提交是類似的,可以通過設置客戶端的令牌來解決。就是在服務器每次生成一個不同的id返回給客戶端,同時保存在 session裏,客戶端提交表單時必須把這個id也返回服務器,程序首先比較返回的id與保存在session裏的值是否一致,如果不一致則說明本次操 作已經被提交過了。可以參看《J2EE核心模式》關於表示層模式的部分。需要注意的是對於使用javascript window.open打開的窗口,一般不設置這個id,或者使用單獨的id,以防主窗口無法操作,建議不要再window.open打開的窗口裏做修改 操作,這樣就可以不用設置。

      (9.)、爲什麼在Weblogic Server中改變session的值後要重新調用一次session.setValue做這個動作主要是爲了在集羣環境中提示Weblogic Server session中的值發生了改變,需要向其他服務器進程複製新的session值。

 (10)、爲什麼session不見了

  排除session正常失效的因素之外,服務器本身的可能性應該是微乎其微的,雖然筆者在iPlanet6SP1加若干補丁的Solaris版本上倒 也遇到過;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題;理論上防火牆或者代理服務器在cookie處理上也有可能會出現問題。

  出現這一問題的大部分原因都是程序的錯誤,最常見的就是在一個應用程序中去訪問另外一個應用程序。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章