httpSession的正確理解
httpSession的正確理解
關於HttpSession的誤解實在是太多了,本來是一個很簡單的問題,怎會搞的如此的復雜呢?下面說說我的理解吧:一個session就是一系列某用戶和服務器間的通訊。服務器有能力分辨出不同的用戶。一個session的建立是從一個用戶向服務器發第一個請求開始,而以用戶顯式結束或session超時為結束。
其工作原理是這樣的:
1.當一個用戶向服務器發送第一個請求時,服務器為其建立一個session,並為此session創建一個標識號;
2.這個用戶隨後的所有請求都應包括這個標識號。服務器會校對這個標識號以判斷請求屬於哪個session。
這種機制不使用IP作為標識,是因為很多機器是通過代理服務器方式上網,沒法區分每一臺機器。
對於session標識號(sessionID),有兩種方式實現:cookies和URL重寫。
HttpSession的使用
我們來看看在API中對session是如何定義和操作的。
當需要為用戶端建立一個session時,servlet容器就創建了一個HttpSession對象。其中存儲了和本session相關的信息。所以,在一個servlet中有多少個不同用戶連接,就會有多少個HttpSession對象。
使用的機理是:
1.從請求中提取HttpSession對象;
2.增加或刪除HttpSession中的屬性;
3.根據需要關閉HttpSession或使其失效。
在請求中有兩個重載的方法用來獲取HttpSession對象。
HttpSession getSession(boolean create)/getSession();作用是提取HttpSession對象,如果沒有自動創建。
獲取到HttpSession對象後,我們就需要使用HttpSession的某些方法去設置和更改某些參數了。如:
void setAttribute(String name, Object value);
Object getAttribute(String name);
void removeAttribute(String name);
在javax.servlet.http包裏一共定義了四個session監聽器接口和與之關聯的兩個session事件。分別是:
HttpSessionAttributeListener and HttpSessionBindingEvent;
HttpSessionBindingListener and HttpSessionBindingEvent;
HttpSessionListener and HttpSessionEvent;
HttpSessionActivationListener and HttpSessionEvent.
他們的繼承關系是:
所有四個接口的父類是java.util.EventListener;
HttpSessionEvent擴展java.util.EventObject;
而HttpSessionBindingEvent又擴展了HttpSessionEvent。
以下分別詳述:
HttpSessionAttributeListener
當session中的屬性被添加,更改,刪除時得到通知。這個接口上節講過,主要看其它三個。
HttpSessionBindingListener
當一個實現了HttpSessionBindingListener的類被加入到HttpSession中(或從中移出)時,會產生HttpBindingEvent事件,而這些事件會被它本身接收到。
本接口定義了兩個方法:
void valueBound(HttpSessionBindingEvent e);
void valueUnbound(HttpSessionBindingEvent e);
當多個實現了HttpSessionBindingListener的類被加入到HttpSession中時,各類的方法只對本類感興趣,不會去理會其它類的加入。
即使是同一類的不同實例間,也是互不關心的(各掃門前雪)。
我們可以看到前兩個接口都對HttpSessionBindingEvent事件做出反應,但機理不同。
HttpSessionAttributeListener是在web.xml中登記的,servlet容器僅創建一個實例,來為任何在session中增加屬性的servlet服務。觸發事件的對象是所有可以轉換為Object的實例。
HttpSessionBindingListener不用在web.xml中登記,在每個servlet中用new創建實例,且僅對本實例向session中的加入(或移出)感興趣。觸發事件的對象僅僅是自己。
HttpSessionListener
對於session的創建和取消感興趣。需要在web.xml中登記。
共有兩個方法:
void sessionCreated(HttpSessionEvent se);
void sessionDestroyed(HttpSessionEvent se);
使用它我們可以容易的創建一個類來對session計數。
也許我們會簡單的考慮使用sessionDestroyed方法來在session結束後做一些清理工作。但是,請註意,當這個方法被調用的時候,session已經結束了,你不能從中提取到任何信息了。因此,我們要另辟蹊徑。
一種通常采用的方法是使用HttpSessionBindingListener接口。在session創建時增加一個屬性,而在session結束前最後一件事將這個屬性刪除,這樣就會觸發valueUnbound方法,所有對session的清理工作可以在這個方法中實現。
HttpSessionActivationListener
當session在分布式環境中跨JVM時,實現該接口的對象得到通知。共兩個方法:
void sessionDidActivate(HttpSessionEvent se);
void sessionWillPassivate(HttpSessionEvent se);
1、HTTP協議本身是“連接-請求-應答-關閉連接”模式的,是一種無狀態協議(HTTP只是一個傳輸協議);
2、Cookie規範是為了給HTTP增加狀態跟蹤用的(如果要精確把握,建議仔細閱讀一下相關的RFC),但不是唯一的手段;
3、所謂Session,指的是客戶端和服務端之間的一段交互過程的狀態信息(數據);這個狀態如何界定,生命期有多長,這是應用本身的事情;
4、由於B/S計算模型中計算是在服務器端完成的,客戶端只有簡單的顯示邏輯,所以,Session數據對客戶端應該是透明的不可理解的並且應該受控於服務端;Session數據要麽保存到服務端(HttpSession),要麽在客戶端和服務端之間傳遞(Cookie或url rewritting或Hidden input);
5、由於HTTP本身的無狀態性,服務端無法知道客戶端相繼發來的請求是來自一個客戶的,所以,當使用服務端HttpSession存儲會話數據的時候客戶端的每個請求都應該包含一個session的標識(sid, jsessionid 等等)來告訴服務端;
6、會話數據保存在服務端(如HttpSession)的好處是減少了HTTP請求的長度,提高了網絡傳輸效率;客戶端session信息存儲則相反;
7、客戶端Session存儲只有一個辦法:cookie(url rewritting和hidden input因為無法做到持久化,不算,只能作為交換session id的方式,即a method of session tracking),而服務端做法大致也是一個道理:容器有個session管理器(如tomcat的org.apache.catalina.session包裏面的類),提供session的生命周期和持久化管理並提供訪問session數據的api;
8、使用服務端還是客戶端session存儲要看應用的實際情況的。一般來說不要求用戶註冊登錄的公共服務系統(如google)采用cookie做客戶端session存儲(如google的用戶偏好設置),而有用戶管理的系統則使用服務端存儲。原因很顯然:無需用戶登錄的系統唯一能夠標識用戶的就是用戶的電腦,換一臺機器就不知道誰是誰了,服務端session存儲根本不管用;而有用戶管理的系統則可以通過用戶id來管理用戶個人數據,從而提供任意復雜的個性化服務;
9、客戶端和服務端的session存儲在性能、安全性、跨站能力、編程方便性等方面都有一定的區別,而且優劣並非絕對(譬如TheServerSide號稱不使用HttpSession,所以性能好,這很顯然:一個具有上億的訪問用戶的系統,要在服務端數據庫中檢索出用戶的偏好信息顯然是低效的,Session管理器不管用什麽數據結構和算法都要耗費大量內存和CPU時間;而用cookie,則根本不用檢索和維護session數據,服務器可以做成無狀態的,當然高效);
10、所謂的“會話cookie”簡單的說就是沒有明確指明有效期的cookie,僅在瀏覽器當前進程生命期內有效,可以被後繼的Set-Cookie操作清除掉。 當程序需要為某個客戶端的請求創建一個session的時候,服務器首先檢查這個客戶端的請求裏是否已包含了一個session標識 - 稱為 session id,如果已包含一個session id則說明以前已經為此客戶端創建過session,服務器就按照session id把這個 session檢索出來使用(如果檢索不到,可能會新建一個),如果客戶端請求不包含session id,則為此客戶端創建一個session並且生成一個與此session相關聯的session id,session id的值應該是一個既不會重復,又不容易被找到規律以仿造的字符串,這個 session id將被在本次響應中返回給客戶端保存。 保存這個session id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動的按照規則把這個標識發揮給服務器。一般這個cookie的名字都是類似於SEEESIONID. 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能夠在集群中被復制或者能夠持久保存或者在必要時server能夠暫時把session交換出內存。 3、如何才能正確的應付客戶端禁止cookie的可能性
對所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見:
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770 Instead, use the HttpServletResponse.encodeURL() method, for example: out.println("<a href=/"" + response.encodeURL("myshop/catalog.jsp") + "/">catalog</a>");
Calling the encodeURL() method determines if the URL needs to be rewritten, and if so, it rewrites it by including the session ID in the URL. The session ID is appended to the URL and begins with a semicolon.
In addition to URLs that are returned as a response to WebLogic Server, also encode URLs that send redirects. For example:
if (session.isNew()) response.sendRedirect (response.encodeRedirectUrl(welcomeURL)); 4、開兩個瀏覽器窗口訪問應用程序會使用同一個session還是不同的session
參見第三小節對cookie的討論,對session來說是只認id不認人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲方式都會對這個問題的答案有影響。
httpSession的正確理解