HttpSession詳解
session的機制
http是無狀態的協議,客戶每次讀取web頁面時,服務器都打開新的會話,而且服務器也不會自動維護客戶的上下文信息,那么要怎么才能實現會話跟蹤呢?session就是一種保存上下文信息的機制,它是針對每一個用戶的,變量的值保存在服務器端,通過SessionID來區分不同的客戶,session是以cookie或URL重寫為基礎的,默認使用cookie來實現,系統會創造一個名為JSESSIONID的輸出返回給客戶端Cookie保存。
保存session id的幾種方式
A.保存session id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動的按照規則把這個標識發送給服務器。
B.由於cookie可以被人為的禁止,必須有其它的機制以便在cookie被禁止時仍然能夠把session id傳遞回服務器,經常采用的一種技術叫做URL重寫,就是把session id附加在URL路徑的后面,附加的方式也有兩種,一種是作為URL路徑的附加信息,另一種是作為查詢字符串附加在URL后面。網絡在整個交互過程中始終保持狀態,就必須在每個客戶端可能請求的路徑后面都包含這個session id。
C.另一種技術叫做表單隱藏字段。就是服務器會自動修改表單,添加一個隱藏字段,以便在表單提交時能夠把session id傳遞回服務器。
session何時被刪除
session在下列情況下被刪除:
A.程序調用HttpSession.invalidate()
B.距離上一次收到客戶端發送的session id時間間隔超過了session的最大有效時間
C.服務器進程被停止
再次注意關閉瀏覽器只會使存儲在客戶端瀏覽器內存中的session cookie失效,不會使服務器端的session對象失效。
URL重寫有什么缺點
對所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL。每個引用你的站點的URL,以及那些返回給用戶的URL(即使通過間接手段,比如服務器重定向中的Location字段)都要添加額外的信息。
這意味着在你的站點上不能有任何靜態的HTML頁面(至少靜態頁面中不能有任何鏈接到站點動態頁面的鏈接)。因此,每個頁面都必須使用servlet或JSP動態生成。即使所有的頁面都動態生成,如果用戶離開了會話並通過書簽或鏈接再次回來,會話的信息都會丟失,因為存儲下來的鏈接含有錯誤的標識信息-該URL后面的SESSION ID已經過期了。
使用隱藏的表單域有什么缺點
僅當每個頁面都是有表單提交而動態生成時,才能使用這種方法。單擊常規的<A HREF..>超文本鏈接並不產生表單提交,因此隱藏的表單域只能用於一系列特定的操作中,比如在線商店的結賬過程。
如何將信息與會話關聯起來
setAttribute會替換任何之前設定的值;如果想要在不提供任何代替的情況下移除某個值,則應使用removeAttribute。這個方法會觸發所有實現了HttpSessionBindingListener接口的值的valueUnbound方法。
會話屬性的類型有什么限制嗎
通常會話屬性的類型只要是Object就可以了。除了null或基本類型,如int,double,boolean。
如果要使用基本類型的值作為屬性,必須將其轉換為相應的封裝類對象
使用isNew來判斷用戶是否為新舊用戶的錯誤做法
public boolean isNew()方法如果會話尚未和客戶程序(瀏覽器)發生任何聯系,則這個方法返回true,這一般是因為會話是新建的,不是由輸入的客戶請求所引起的。
但如果isNew返回false,只不過是說明他之前曾經訪問該Web應用,並不代表他們曾訪問過我們的servlet或JSP頁面。
因為session是與用戶相關的,在用戶之前訪問的每一個頁面都有可能創建了會話。因此isNew為false只能說用戶之前訪問過該Web應用,session可以是當前頁面創建,也可能是由用戶之前訪問過的頁面創建的。
正確的做法是判斷某個session中是否存在某個特定的key且其value是否正確
是否只要關閉瀏覽器,session就消失了
程序一般都是在用戶做log off的時候發個指令去刪除session,然而瀏覽器從來不會主動在關閉之前通知服務器它將要被關閉,因此服務器根本不會有機會知道瀏覽器已經關閉。服務器會一直保留這個會話對象直到它處於非活動狀態超過設定的間隔為止。
之所以會有這種錯誤的認識,是因為大部分session機制都使用會話cookie來保存session id,而關閉瀏覽器后這個session id就消失了,再次連接到服務器時也就無法找到原來的session。
如果服務器設置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發出的HTTP請求報頭,把原來的session id發送到服務器,則再次打開瀏覽器仍然能夠找到原來的session。
恰恰是由於關閉瀏覽器不會導致session被刪除,迫使服務器為session設置了一個失效時間,當距離客戶上一次使用session的時間超過了這個失效時間時,服務器就可以認為客戶端已經停止了活動,才會把session刪除以節省存儲空間。
由此我們可以得出如下結論:
關閉瀏覽器,只會是瀏覽器端內存里的session cookie消失,但不會使保存在服務器端的session對象消失,同樣也不會使已經保存到硬盤上的持久化cookie消失。
如何使用會話顯示每個客戶的訪問次數
由於客戶的訪問次數是一個整型的變量,但session的屬性類型中不能使用int,double,boolean等基本類型的變量,所以我們要用到這些基本類型的封裝類型對象作為session對象中屬性的值
但像Integer是一種不可修改(Immutable)的數據結構:構建后就不能更改。這意味着每個請求都必須創建新的Integer對象,之后使用setAttribute來代替之前存在的老的屬性的值。例如:
HttpSession session = request.getSession();
SomeImmutalbeClass value = (SomeImmutableClass)session.getAttribute(“SomeIdentifier”);
if (value= =null){
value = new SomeImmutableClass(…); // 新創建一個不可更改對象
}else{
value = new SomeImmutableClass(calculatedFrom(value)); // 對value重新計算后創建新的對象
}
session.setAttribute(“someIdentifier”,value); // 使用新創建的對象覆蓋原來的老的對象
如何使用會話累計用戶的數據
使用可變的數據結構,比如數組、List、Map或含有可寫字段的應用程序專有的數據結構。通過這種方式,除非首次分配對象,否則不需要調用setAttribute。例如
HttpSession session = request.getSession();
SomeMutableClass value = (SomeMutableClass)session.getAttribute(“someIdentifier”);
if(value = = null){
value = new SomeMutableClass(…);
session.setAttribute(“someIdentifier”,value);
}else{
value.updateInternalAttribute(…); // 如果已經存在該對象則更新其屬性而不需重新設置屬性
}