在Web伺服器端編程中,工作階段狀態管理是一個經常必須考慮的重要問題。本文分析JSP/Servlet的會話管理機制及其所面臨的問題,然後提出了一種改進的會話管理方法。
一、Servlet的會話管理機制
根據設計,HTTP是一種無狀態的協議。它意味著Web應用並不瞭解有關同一使用者以前請求的資訊。維持工作階段狀態資訊的方法之一是使用Servlet或者JSP容器提供的會話跟蹤功能。Servlet API規範定義了一個簡單的HttpSession介面,通過它我們可以方便地實現會話跟蹤。
HttpSession介面提供了儲存和返回標準會話屬性的方法。標準會話屬性如工作階段識別項、應用資料等,都以“名字-值”對的形式儲存。簡而言之,HttpSession介面提供了一種把對象儲存到記憶體、在同一使用者的後繼請求中提取這些對象的標準辦法。在會話中儲存資料的方法是setAttribute(String s, Object o),從會話提取原來所儲存對象的方法是getAttribute(String s)。
在HTTP協議中,當使用者不再活動時不存在顯式的終止訊號。由於這個原因,我們不知道使用者是否還要再次返回,如果不採取某種方法解決這個問題,記憶體中會積累起大量的HttpSession對象。
為此,Servlet採用“逾時限制”的辦法來判斷使用者是否還在訪問:如果某個使用者在一定的時間之內沒有發出後繼請求,則該使用者的會話被作廢,他的HttpSession對象被釋放。會話的預設逾時間隔由Servlet容器定義。這個值可以通過getMaxInactiveInterval方法獲得,通過setMaxInactiveInterval方法修改,這些方法中的逾時時間以秒計。如果會話的逾時時間值設定成-1,則會話永不逾時。Servlet可以通過getLastAccessedTime方法獲得當前請求之前的最後一次訪問時間。
要獲得HttpSession對象,我們可以調用HttpServletRequest對象的getSession方法。為了正確地維持工作階段狀態,我們必須在發送任何應答內容之前調用getSession方法。
使用者會話既可以用手工方法作廢,也可以自動作廢。作廢會話意味著從記憶體中刪除HttpSession對象以及它的資料。例如,如果一定時間之內(預設30分鐘)使用者不再發送請求,Java Web Server自動地作廢他的會話。
Servlet/JSP會話跟蹤機制有著一定的局限,比如:
· 會話對象儲存在記憶體之中,佔用了可觀的資源。
· 會話跟蹤依賴於Cookie。由於各種原因,特別是安全上的原因,一些使用者關閉了Cookie。
· 會話跟蹤要用到伺服器建立的工作階段識別項。在多個Web伺服器以及多個JVM的環境中,Web伺服器不能識別其他伺服器建立的工作階段識別項,會話跟蹤機制無法發揮作用。 要深入理解會話跟蹤機制,首先我們必須理解在Servlet/JSP容器中會話如何運作。
二、工作階段識別項
每當新使用者請求一個使用了HttpSession對象的JSP頁面,JSP容器除了發回應答頁面之外,它還要向瀏覽器發送一個特殊的數字。這個特殊的數字稱為“工作階段識別項”,它是一個唯一的使用者識別碼。此後,HttpSession對象就駐留在記憶體之中,等待同一使用者返回時再次調用它的方法。
在用戶端,瀏覽器儲存工作階段識別項,並在每一個後繼請求中把這個工作階段識別項發送給伺服器。工作階段識別項告訴JSP容器當前請求不是使用者發出的第一個請求,伺服器以前已經為該使用者建立了HttpSession對象。此時,JSP容器不再為使用者建立新的HttpSession對象,而是尋找具有相同工作階段識別項的HttpSession對象,然後建立該HttpSession對象和當前請求的關聯。
工作階段識別項以Cookie的形式在伺服器和瀏覽器之間傳送。如果瀏覽器不支援Cookie又如何呢?此時,對伺服器的後繼請求將不會帶有工作階段識別項。結果,JSP容器認為該請求來自一個新使用者,它會再建立一個HttpSession對象,而以前建立的HttpSession對象仍舊駐留在記憶體中,但該使用者以前的會話資訊卻丟失了。
另外,Servlet/JSP容器只認可它自己建立的工作階段識別項。如果同一Web應用在“Web農場”(Web farm)的多台伺服器上運行,則必須存在這樣一種機制:保證來自同一使用者的請求總是被定向到處理該使用者第一次請求的伺服器。