來源:
http://www.iteye.com/topic/960652
http://godsend-jin.iteye.com/blog/1004386
--------------------------------------------------------------------

最近在做登錄和權限控制模塊,用到了session,發現session的好多方法都不熟悉,而且以前也聽說過JsessionId 之類session竊取的事,

對這些一直都是一知半解。今天索性google了很多資料,先上sun的官網去看session的文檔了解一些方法,又找了別人關于session的看法。

總結如下:

      1,session是什么?  what

          session經常譯為會話,以打電話為例,從開始撥號到掛斷電話就是你會話的生存周期。

      2,session 做什么用的  why?

          首先舉個例子:

                咖啡店舉行 消費滿5杯咖啡贈送一杯的活動,可每個人一次消費5杯的時候非常少。這時候有3種辦法:

                1,店員看到每個顧客時都能記住其消費了多少杯,從而給其優惠,這是協議本身具有狀態

                2,給每個顧客一個卡片,上面記錄顧客的每次消費,這是客戶端保存狀態

                3,給每個顧客一個卡片,卡片上只有一個編號,顧客每次的消費記錄在店里,這就是 服務端有狀態

          而http本身是無狀態的,所以我們只能使用2,3中方法,來保存一些信息。

          實際采用的是第3種方法,服務器段保存一次會話所有的信息,并生成一個唯一的id,這個id沒有規律而且不會重復,將這個id傳回到客戶段,

保存到cookie中。每次訪問服務器時,客戶端都會偷偷將這個id傳到服務器,服務器根據id查到這次會話保存的內容。就能實現會話中共享一些數據。

     3,session怎樣創建和銷毀 ? how

         session是保存在內存中的,所以會有一些性能上的影響。因此本著這個原則,session是只有在使用到的時候才會被創建,如果始終沒有用到

session,這個session是永遠不會被創建的。

        比如: 訪問servlet ,只要你代碼中沒有 request.getSession()或request.getSession(true);這兩行是等價的,那session是不會創建。

又 當你訪問靜態頁面時,根本不會生成servlet,所以也不會創建session。

       下面解釋一些疑惑: session是第一次請求時創建的?

  大家都知道 jsp是被編譯成servlet才執行的,問題就在jsp編譯的過程。

 jsp中有個<%@ page session="true/false"%> 這個開關表示是否創建session,當你不寫這行時,它會默認給你加上這句。所以會造成上面的疑惑。

當然還有一些標簽中可能有getSession()操作,會產生一些不必要的session。

       session只能在服務端銷毀,有三種途徑: 1,到達session的最大請求間隔時間時,2,session。invalidate()

 3,服務器進程當掉。

       這里也有一些疑惑: 瀏覽器關閉時,session就會注銷。

       首先瀏覽器關閉時,瀏覽器并沒有給服務器發送任何消息,所以服務器不會知道瀏覽器何時關閉了。

 上面我們知道取得session 是因為瀏覽器cookie中有sessionid,而普通cookie通常會是會話cookie,也就是說瀏覽器關閉時,這個cookie會被注銷,

所以當你再訪問服務器時就沒有sessionid了,所以造成session關閉了的假象,如果昵稱通過特殊方法將sessionid傳遞給服務器,你會發現session還在。

如果想讓cookie保存時間長一些,就需要手動指定cookie的過期時間

 

4,實際項目中的難點:

     1,瀏覽器禁用cookie

      這就沒辦法保存sessionid了,可以采用url重寫,轉發,加隱藏字段等方法來將sessionid傳給服務器。

     如:  baidu.com:jsessionid=adfasdfasdfasdfasdfafdadf?asdfasdf

             baidu.com?jsessionid=asdfasdfasdfadsfad&&adfdf

 這根據服務器的不同實現,第一種可以將普通參數區分開。

 

     2,多人共用session的問題

        例: a 訪問 baidu.com ,但他沒有帳號,于是他將連接 baidu.com/login.jsp?jsessionid=adsfasdfad(這個a的sessionid) 發給B, B登錄

后,a就相當于用b的帳號登錄了。你們可以在在本地試試。

        解決方法: 當發現通過sessionid從url指定時, 創建一個新的session,將舊session的信息復制到 新sessoin中,然后將新session注銷。

就能防止上面那種情況了。

    3,一個帳號多地方登錄

       比如: 你用abc帳號登錄了baidu.com,有打開了一個瀏覽器,又用abc帳號登錄了一次。當不設計敏感操作時,這無所謂,而當你做一些敏感操

作時就必須禁止這樣情況,防止同時操作,造成重復操作,或者數據損壞。

     解決方法: 監聽session,將username和sessionid對應起來,當username再次登錄時,注銷掉以前的session,保存現在的session,這也是

一種比較不錯的方案。

 

這是 sghcel 畫的圖,挺不錯的:

 



其他:
 1session在何時被創建 
    一個常見的誤解是以為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
Title
  嚴格的講,做不到這一點。可以做一點努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監視瀏覽器的關閉動作,然后向服務器發送
一個請求來刪除
session。但是對于瀏覽器崩潰或者強行殺死進程這些非常規手段仍然無能為力。


    4
、有個HttpSessionListener是怎么回事 

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

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


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


    6
、如何才能正確的應付客戶端禁止cookie的可能性
 
    對所有的URL使用URL重寫,包括超鏈接,formaction,和重定向的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值。


   10HttpSession 和 hibernate session 有什么區別?
httpSession :

它的產生:J2EE的Web程序在運行的時候,會給每一個新的訪問者建立一個HttpSession,這個Session是用戶身份的唯一表示。注意,是容器

(Tomcat,Resin)自動創建的。

用途:存放這個用戶的一些經常被用到的信息,例如:用戶名,權限。例如在購物車程序里,存放用戶買的商品。

銷毀:一定時間(跟容器有關)內,用戶無任何動作,session自動銷毀。

得到的方法:
HttpSession session = request.getSession();
常用方法setAttribute
session.setAttribute(key,value);
這樣在另一個jsp或者Servlet里,可以用
session.getAttribute(key);得到value
類似一個Map


hibernate session

它是hibernate操作數據庫的一個句柄對象。它跟上面那個Session唯一的相似處就是名字有點像,其他沒任何一樣的地方。
它是hibernate表示操作數據庫的一個會話