Sessions
超文本傳輸協(xié)議(HTTP)被設(shè)計為無狀態(tài)協(xié)議。 要構(gòu)建有效的Web應(yīng)用程序,必須將來自特定客戶端的請求相互關(guān)聯(lián)。 隨著時間的推移,會話跟蹤的許多策略都在不斷發(fā)展,但程序員直接使用它們都很困難或麻煩。
本規(guī)范定義了一個簡單的HttpSession接口,該接口允許servlet容器使用多種方法中的任何一種來跟蹤用戶的會話,而不會使Application Developer陷入任何一種方法的細微差別。
1. session追蹤機制
以下幾節(jié)描述了追蹤一個用戶會話的方法。
1.1 Cookies
通過HTTP cookie進行會話跟蹤是最常用的會話跟蹤機制,要求被所有servlet容器支持。
容器向客戶端發(fā)送一個cookie。 然后,客戶端會將每個后續(xù)請求上的cookie返回給服務(wù)器,明確地將該請求與會話相關(guān)聯(lián)。 會話跟蹤cookie的標準名稱必須是JSESSIONID.Containers可允許通過容器特定配置來定制會話跟蹤cookie的名稱。
所有servlet容器必須提供配置容器是否將會話跟蹤cookie標記為HttpOnly的能力。 已建立的配置必須適用于尚未建立上下文特定配置的所有上下文(有關(guān)更多詳細信息,請參閱SessionCookieConfig javadoc)。
如果Web應(yīng)用程序為其會話跟蹤cookie配置自定義名稱,則如果會話ID在URL中進行了編碼(前提是已啟用URL重寫),則同樣的自定義名稱也將用作URI參數(shù)的名稱。
1.2 SSL會話
Secure Sockets Layer, the encryption technology used in the HTTPS protocol, has a built-in mechanism allowing multiple requests from a client to be unambiguously identified as being part of a session. A servlet container can easily use this data to define a session.
安全套接字層是HTTPS協(xié)議中使用的加密技術(shù),它有一個內(nèi)置的機制,可以允許客戶機的多個請求被明確標識為會話的一部分。servlet容器可以很容易地使用這些數(shù)據(jù)來定義會話。
1.3 URL重寫
URL rewriting is the lowest common denominator of session tracking. When a client will not accept a cookie, URL rewriting may be used by the server as the basis for session tracking. URL rewriting involves adding data, a session ID, to the URL path that is interpreted by the container to associate the request with a session.
The session ID must be encoded as a path parameter in the URL string. The name of the parameter must be jsessionid. Here is an example of a URL containing encoded path information:
http://www.example.com/catalog/index.html;jsessionid=1234
URL rewriting exposes session identifiers in logs, bookmarks, referer headers, cached HTML,and the URL bar. URL rewriting should not be used as a session tracking mechanism where cookies or SSL sessions are supported and suitable
URL重寫是會話跟蹤的最小公分母。當客戶端不接受cookie時,URL重寫可能被服務(wù)器用作會話跟蹤的基礎(chǔ)。URL重寫涉及到將數(shù)據(jù)(一個會話ID)添加到由容器解釋的URL路徑,以將請求與會話關(guān)聯(lián)起來。
會話ID必須編碼為URL字符串中的路徑參數(shù)。參數(shù)的名稱必須是jsessionid。下面是一個包含編碼路徑信息的URL示例:
http://www.example.com/catalog/index.html;jsessionid = 1234
URL重寫在日志、書簽、引用標頭、緩存的HTML和URL欄中公開會話標識符。URL重寫不應(yīng)該被用作一個會話跟蹤機制,在這個機制中,cookie或SSL會話是受支持的和合適的。
1.4 會話的完整性
Web容器必須能夠支持HTTP會話,同時為不支持使用cookie的客戶端提供HTTP請求。為了滿足這個需求,Web容器通常支持URL重寫機制。
2.創(chuàng)建會話
,當會話只是一個預(yù)期的會話且尚未建立,那它會被認為是“新”的。因為HTTP是基于請求-響應(yīng)的協(xié)議,所以在客戶端“加入”之前HTTP會話被認為是新的。當會話跟蹤信息被返回到服務(wù)器,表明已經(jīng)建立了會話時,客戶機加入會話。在客戶機加入會話之前,不能假定客戶機的下一個請求將被視為會話的一部分。
如果下列任何一項是正確的會話將被認為是“新”:
- 客戶還不了解會話
- 客戶選擇不加入一個會話
這些條件定義了servlet容器沒有將請求與之前的請求關(guān)聯(lián)起來的機制的情況。
Servlet開發(fā)人員必須設(shè)計他的應(yīng)用程序來處理客戶端沒有、不能或不會加入會話的情況。
與每個會話相關(guān)聯(lián),有一個包含一個獨特的標識符的字符串,這被稱為會話id。會話id的值可以通過調(diào)用javax.servlet.http.HttpSession.getId()獲取,和創(chuàng)建后可以通過調(diào)用javax.servlet.http.HttpServletRequest.changeSessionId()改變。
3. session范圍
HttpSession對象必須在應(yīng)用程序(或servlet上下文)級別范圍內(nèi)。在底層機制,例如用于建立會話的cookie,對于不同的上下文可以是相同的,但是引用的對象,包括該對象中的屬性,不能被容器在上下文之間共享。
要用一個例子來說明這一需求:如果一個servlet使用RequestDispatcher在另一個Web應(yīng)用程序中調(diào)用servlet,那么為這個servlet創(chuàng)建并可見的任何會話都必須與調(diào)用servlet可見的會話不同。
此外,上下文的會話必須可被請求恢復(fù)到該上下文,而不管它們的關(guān)聯(lián)上下文是否被直接訪問或在創(chuàng)建會話時作為請求分派的目標。
4.綁定屬性到Session
servlet可以通過名稱將對象屬性綁定到HttpSession實現(xiàn)。任何綁定到會話的對象都可用于屬于同一個ServletContext的任何其他servlet,并處理被標識為同一會話的一部分的請求。
當某些對象被放置或從會話中刪除時,可能需要通知。此信息可以通過對象實現(xiàn)HttpSessionBindingListener接口獲得。該接口定義了以下方法,該方法將指示被綁定到的對象或從會話中釋放的對象。
- valueBound
- valueUnbound
在通過HttpSession接口的getAttribute方法提供對象之前,必須調(diào)用valueBound方法。在對象不再可以通過HttpSession接口的getAttribute方法可達之后,必須調(diào)用valueUnbound方法。
5.會話超時
In the HTTP protocol, there is no explicit termination signal when a client is no longer active. This means that the only mechanism that can be used to indicate when a client is no longer active is a time out period.
The default time out period for sessions is defined by the servlet container and can be obtained via the getSessionTimeout method of the ServletContext interface or the getMaxInactiveInterval method of the HttpSession interface.
This time out can be changed by the Developer using the setSessionTimeout method of the ServletContext interface or the setMaxInactiveInterval method of the HttpSession interface. The time out periods used by session timeout methods are defined in minutes. The time out periods used by max active interval methods are defined in seconds. See the javadoc for setSessionTimeout for additional normative requirements. By definition, if the time out period for a session is set to 0 or lesser value, the session will never expire. The session invalidation will not take effect until all servlets using that session have exited the service method. Once the session invalidation is initiated, a new request must not be able to see that session.
在HTTP協(xié)議中,當客戶端不再活動時,是沒有顯式的終止信號的。這意味著,唯一可以用來指示客戶端不再活動的機制是超時時間。
會話的默認超時時間由servlet容器定義,可以通過ServletContext接口的getSessionTimeout方法或HttpSession接口的getMaxInactiveInterval方法獲得。
這個時間可以由開發(fā)人員使用ServletContext接口的setSessionTimeout方法或HttpSession接口的setMaxInactiveInterval方法來更改。會話超時方法使用的超時時間定義為分鐘。max activeinterval方法所使用的超時時間定義為秒。請參見javadoc以獲得額外的規(guī)范需求。根據(jù)定義,如果會話的超時時間設(shè)置為0或更低的值,會話將不會過期。在使用該會話的所有servlet退出服務(wù)方法之前,會話將不會失效。一旦會話失效開始,新的請求就不能看到會話。
6. 最后訪問時間
HttpSession接口的getLastAccessedTime方法允許servlet在當前請求之前確定會話上次訪問的時間。當會話的一部分請求首先由servlet容器處理時,會話被認為是被訪問的。
7. 重要的Session語義
7.1 線程問題
執(zhí)行請求線程的多個servlet可以同時對同一個會話對象進行活動訪問。容器必須確保對表示會話屬性的內(nèi)部數(shù)據(jù)結(jié)構(gòu)的操作以線程安全的方式執(zhí)行。開發(fā)人員負責線程安全訪問屬性對象本身。這將保護HttpSession對象內(nèi)的屬性集合不受并發(fā)訪問,從而消除了應(yīng)用程序?qū)е略摷媳黄茐牡臋C會。除非在規(guī)范的其他地方(例如第7.7.1節(jié),在第7-67頁的會話對象上的“線程問題”)中明確聲明,否則從請求或響應(yīng)中獲得的對象必須被假定為非線程安全的。這包括,但不限于返回的PrintWriter ServletResponse.getWriter()和返回的OutputStream ServletResponse.getOutputStream()
7.2 分布式環(huán)境
在分布式的應(yīng)用程序中,所有屬于會話的請求必須一次由一個JVM處理。容器必須能夠正確地使用setAttribute或putValue方法將所有放置到HttpSession類實例中的對象處理。為了滿足這些條件,我們實施了以下限制:
- 容器必須接受實現(xiàn)Serializable接口的對象。
- 容器可以選擇支持HttpSession中其他指定對象的存儲,例如對Enterprise JavaBeans組件和事務(wù)的引用。
- 遷移會話將由特定容器設(shè)施處理。
當分布式 servlet 容器不支持必需的會話遷移存儲對象機制時容器必須拋出 IllegalArgumentException。
分布式 servlet 容器必須支持遷移的對象實現(xiàn) Serializable 的必要機制。
這些限制意味著開發(fā)人員可以確保在非分布式容器中不存在其他并發(fā)性問題。
容器提供程序可以通過將會話對象及其內(nèi)容(從分布式系統(tǒng)的任何活動節(jié)點)移動到系統(tǒng)的不同節(jié)點,從而確保負載均衡和故障轉(zhuǎn)移等服務(wù)特性的可伸縮性和質(zhì)量。
如果分布式容器持久化或遷移會話以提供服務(wù)特性的質(zhì)量,它們并不局限于使用本機JVM序列化機制來序列化httpsession及其屬性。開發(fā)人員不能保證容器會在會話屬性上調(diào)用readObject和writeObject方法,如果他們實現(xiàn)了這些方法,但保證它們的屬性的可序列化閉包將被保留。
容器必須在遷移會話期間通知任何實現(xiàn)HttpSessionActivationListener的會話屬性。它們必須在會話序列化之前通知偵聽器,并在會話反序列化之后激活。編寫分布式應(yīng)用程序的應(yīng)用程序開發(fā)人員應(yīng)該意識到,由于容器可能在多個Java虛擬機中運行,因此開發(fā)人員不能依賴靜態(tài)變量來存儲應(yīng)用程序狀態(tài)。它們應(yīng)該使用企業(yè)bean或數(shù)據(jù)庫存儲這些狀態(tài)。
7.3 客戶端語義
Due to the fact that cookies or SSL certificates are typically controlled by the Web browser process and are not associated with any particular window of the browser,requests from all windows of a client application to a servlet container might be part of the same session. For maximum portability, the Developer should always assume that all windows of a client are participating in the same session.
由于cookie或SSL證書通常由Web瀏覽器進程控制,且不與瀏覽器的任何特定窗口相關(guān)聯(lián),所以從客戶機應(yīng)用程序的所有窗口向servlet容器請求可能是同一會話的一部分。為了獲得最大的可移植性,開發(fā)人員應(yīng)該始終假設(shè)客戶的所有窗口都參與了相同的會話。