Session機制

Session機制
除了使用Cookie,Web應用程序中還經常使用Session來記錄客戶端狀態。Session是服務端使用的一種記錄客戶端狀態的機制,使用上比Cookie簡單一些,響應的也增加了服務器的存儲壓力。
Session技術是服務端的解決方案,它是通過服務器來保持狀態的。由於Session這個詞彙包含的語義很多,因此需要在這裏明確Session的含義。
首先,我們通常把Session翻譯成會話,因此我們可以把客戶端瀏覽器與服務器之間一系列交互的動作稱爲一個Session。從這個語義出發,我們會提到Session持續的時間,會提到在Session過程中進行了什麼操作等等;其次,Session指的是服務器端爲客戶端所開闢的存儲空間,在其中保存的信息就是用於保持狀態。從這個語義出發,我們則會提到往Session中存放什麼內容,如何根據鍵值從Session中獲取匹配的內容等。
要使用Session,第一步當然是創建Session了。那麼Session在何時創建呢?當然還是再服務器端程序運行的過程中創建的。不同語言實現的應用程序有不同創建Session的方法,而在Java中是通過調用HttpServletRequest的getSession方法(使用true作爲參數)創建的。
在創建了Session的同時,服務器會爲該Session生成唯一的SessionId,而這個SessionId在隨後的請求中會被用來重新獲得已經創建的Session,在Session被創建之後,就可以調用Session相關的方法往Session中增加內容了。
而這些內容只會保存在服務器中,發到客戶端的只有SessionId,當客戶端再次發送請求的時候,會將這個SessionId帶上,服務器接收到請求之後就根據SessionId找到相應的Session,從而再次使用。正是這樣一個過程,用戶的狀態得以保持。



什麼是Session
Session是另一種記錄客戶狀態的機制,不同的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器吧客戶端信息以某種形式記錄在服務器上。這就是Session。客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態就可以了。
如果說Cookie機制是通過檢查客戶身上的“通行證”來確定客戶身份的話,那麼Session機制就是通過檢查服務器上的"客戶明細表"來確認客戶身份。Session相當於程序在服務器上建立的一份客戶檔案,客戶來訪的時候只需要查詢客戶檔案表就可以了。


Session的生命週期
Session保存在服務器端。爲了獲得更高的存取速度,服務器一般把Session放在內存裏。每個用戶都會有一個獨立的Session,如果Session內容太過複雜,當大量客戶訪問服務器時可能會導致內存溢出。因此,Session裏的信息應該儘量精簡。
Session在用戶第一次訪問服務器的時候自動創建。需要注意只有訪問JSP、Servlet等程序時,纔會創建Session,只訪問HTML、IMAGE等靜態資源並不會創建Session。如果尚未生成Session,也可以使用request.getSession(true)強制生成Session。
Session生成後,只要用戶繼續訪問,服務器就會更新Session的最後訪問時間,並維護該Session。用戶每訪問服務器一次,無論是否讀寫Session,服務器都認爲該用戶的Session“活躍(active)”了一次。



Session的有效期
由於會有越來越多的用戶訪問服務器,因此Session也會越來越多。爲了防止內存溢出,服務器會把長時間沒有活躍的Session從內存刪除。這個時間就Session的超時時間,如果超過了超時時間沒有訪問服務器,Session就自動失效了。
Session的超時時間爲maxInactiveInterval屬性,可以通過getMaxInactiveInterval()獲取,通過setMaxInactiveInterval()修改。
Session的超時時間也可以在web.xml中修改,另外,調用Session的invalidate()方法可以使Session失效。


Session的常用方法
void setAttribute(String value,Object value):設置Session屬性。value參數可以爲任何Java Object。通常爲JavaBean,value信息不宜過大。
String getAttribute(String attribute):返回Session屬性
Enumeration getAttributeNames():返回Session中存在的屬性名
void removeAttribute(String attribute):移除Session屬性
String getId():返回Session的ID。該ID由服務器自動創建,不會重複。
long getCreationTime():返回Session的創建日期。返回類型爲long,常被轉化爲Date類型,例如:Date createTime = new Date(session.getCreationTime())
long getLastAccessedTime():返回Session的最後活躍時間。返回類型爲long int 
getMaxInactiveInterval():返回Session的超時時間。單位爲秒。超過該時間沒有訪問,服務器認爲該Session失效
void setMaxInactiveInterval(int second):設置Session的>超時時間。單位爲秒 
void putValue(String attribute, Object value):不推薦的方法。已經被setAttribute(String attribute, Object Value)替代
Object getValue(String attribute):不被推薦的方法。已經被getAttribute(String attr)替代
boolean isNew():返回該Session是否是>新創建的 void invalidate():使該Session失效


Tomcat中Session的默認超時時間爲20分鐘,通過setMaxInactiveInterval(int second)修改超時時間。
也可以修改web.xml中的默認超時時間,例如修改成60分鐘
<session-config>
   <session-timeout>60</session-timeout>
</session-config>


注意:參數的單位爲分鐘,而setMaxInactiveInterval(int s)單位爲秒。
在server.xml中定義context時採用如下定義(單位爲秒):
<Context path="/livsorder" docBase="/home/httpd/html/livsorder" defaultSessionTimeOut="3600" isWARExpanded="true"
    isWARValidated="false" isInvokerEnabled="true"
    isWorkDirPersistent="false"/>




Session對瀏覽器的要求
雖然Session保存在服務器,對客戶端是透明的,它的運行仍需要客戶端瀏覽器的支持。這是因爲Session需要使用Cookie作爲識別標識。
Http協議是無狀態的,Session不能根據http連接判斷是否是同一用戶。因此服務器向客戶端發送一個名爲JSESSIONID的Cookie,它的值爲該Session的id(也就是HttpSession.getId()的返回值),Session根據該Cookie來判斷是否是同一用戶。
該Cookie是服務器自動生成的,它的maxAge屬性一般爲-1,表示僅當前瀏覽器內有效,並且各瀏覽器窗口間不共享,關閉瀏覽器就會失效。
因此同一個機器的兩個瀏覽器窗口訪問服務器時,會生成不同的Session,但是由瀏覽器窗口內的鏈接,腳本打開的新窗口(也就是說不是由雙擊桌面瀏覽器圖標打開的窗口)除外,這類子窗口共享父窗口的Cookie,因此會共享一個Session。
注意:新打開的窗口會生成新的Session,但子窗口除外。子窗口會共用父窗口的Session。例如,在鏈接上右擊,在彈出的快捷菜單中選擇“在新窗口打開時”,子窗口便可以訪問父窗口的Session。
如果客戶端瀏覽器將Cookie功能禁用,或者不支持Cookie怎麼辦?例如,絕大多數的手機瀏覽器都不支持Cookie。Java Web提供了另一種解決方案:URL地址重寫。



URL地址重寫
URL地址重寫是對客戶端不支持Cookie的解決方案。URL地址重寫的原理是將該用戶Session的id信息重寫到URL地址中。服務器能夠解析重寫後的URL獲取Session的id。這樣即使客戶端不支持Cookie,也可以使用Session來記錄用戶狀態。HttpServletResponse類提供了encodeURL(Stringurl)實現URL地址重寫,例如:
<td>
    <a href="<%=response.encodeURL("index.jsp?c=1&wd=Java") %>"> 
    Homepage</a>
</td>
該方法會自動判斷客戶端是否支持Cookie。如果客戶端支持Cookie,會將URL原封不動地輸出來。如果客戶端不支持Cookie,則會將用戶Session的id重寫到URL中。重寫後的輸出可能是這樣的:
<td>
    <a href="index.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E?c=1&wd=Java">Homepage</a>
</td>
即在文件名的後面,在URL參數的前面添加了字符串“;jsessionid=XXX”。其中XXX爲Session的id。分析一下可以知道,增添的jsessionid字符串既不會影響請求的文件名,也不會影響提交的地址欄參數。用戶單擊這個鏈接的時候會把Session的id通過URL提交到服務器上,服務器通過解析URL地址獲得Session的id。


如果是頁面重定向(Redirection),URL地址重寫可以這樣寫:
<%
    if(“administrator”.equals(userName)) {
        response.sendRedirect(response.encodeRedirectURL(“administrator.jsp”));
        return;
    }
%>
效果跟response.encodeURL(String url)是一樣的:如果客戶端支持Cookie,生成原URL地址,如果不支持Cookie,傳回重寫後的帶有jsessionid字符串的地址。
對於WAP程序,由於大部分的手機瀏覽器都不支持Cookie,WAP程序都會採用URL地址重寫來跟蹤用戶會話。
注意:TOMCAT判斷客戶端瀏覽器是否支持Cookie的依據是請求中是否含有Cookie。儘管客戶端可能會支持Cookie,但是由於第一次請求時不會攜帶任何Cookie(因爲並無任何Cookie可以攜帶),URL地址重寫後的地址中仍然會帶有jsessionid。當第二次訪問時服務器已經在瀏覽器中寫入Cookie了,因此URL地址重寫後的地址中就不會帶有jsessionid了。
由於Cookie可以被人爲的禁止,必須有其他機制以便在Cookie被禁止時仍然能夠把session id傳遞迴服務器。經常被使用的一種技術叫做URL重寫,就是把session id直接附加在URL路徑的後面,附加方式也有兩種: 一種是作爲URL路徑的附加信息,表現形式爲http://...../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764 一種是作爲查詢字符串附加在URL後面,表現形式爲http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
這兩種方式對於用戶來說是沒有區別的,只是服務器在解析的時候處理的方式不同,採用第一種方式也有利於把session id的信息和正常程序參數區分開來。爲了在整個交互過程中始終保持狀態,就必須在每個客戶端可能請求的路徑後面都包含這個session id。

另一種技術叫做表單隱藏字段。就是服務器會自動修改表單,添加一個隱藏字段,以便在表單提交時能夠把session id傳遞迴服務器。比如下面的表單:
<form name="testform" action="/xxx">
    <input type="text">
</form>
在被傳遞給客戶端之前將被改寫成:
<form name="testform" action="/xxx">
    <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
    <input type="text">
</form>
在談論session機制的時候,常常聽到這樣一種誤解“只要關閉瀏覽器,session就消失了”。其實可以想象一下會員卡的例子,除非顧客主動對店家提出銷卡,否則店家絕對不會輕易刪除顧客的資料。對session來說也是一樣的,除非程序通知服務器刪除一個session,否則服務器會一直保留,程序一般都是在用戶做log off的時候發個指令去刪除session。然而瀏覽器從來不會主動在關閉之前通知服務器它將要關閉,因此服務器根本不會有機會知道瀏覽器已經關閉,之所以會有這種錯覺,是大部分session機制都使用會話cookie來保存session id,而關閉瀏覽器後這個 session id就消失了,再次連接服務器時也就無法找到原來的session。如果服務器設置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發出的HTTP請求頭,把原來的session id發送給服務器,則再次打開瀏覽器仍然能夠找到原來的session。

恰恰是由於關閉瀏覽器不會導致session被刪除,迫使服務器爲seesion設置了一個失效時間,當距離客戶端上一次使用session的時間超過這個失效時間時,服務器就可以認爲客戶端已經停止了活動,纔會把session刪除以節省存儲空間。


Session中禁止使用Cookie

既然WAP上大部分的客戶瀏覽器都不支持Cookie,索性禁止會話使用Cookie,統一使用URL地址重寫會更好一些.Java Web規範支持通過配置的方式禁用Cookie。下面舉例說一下怎樣通過配置禁止使用的cookie。


打開項目sessionWeb的WebRoot目錄下的META-INF文件夾(跟WEB-INF文件夾同級,如果沒有則創建),打開context.xml(如果沒有則創建),編輯內容如下:/ META-INF / context .xml:
<?xml version ='
    1.0'coding ='UTF-8'?> <Context path =“/ sessionWeb”cookies =“false”>
</ Context>

或者修改Tomcat全局的conf / context.xml,修改內容如下:context.xml:
<! - 將爲每個web應用程序加載此文件的內容 - >
<Context cookies =“false”>
    <! - ...中間代碼略 - >
</ Context>

部署後TOMCAT便不會自動生成名JSESSIONID的餅乾,會議也不會以餅乾爲識別標誌,而僅僅以重寫後的URL地址爲識別標誌了

注意:該配置只是禁止會話使用的Cookie作爲識別標誌,並不能阻止其他的Cookie讀寫。也就是說服務器不會自動維護名爲JSESSIONID的Cookie了,但是程序中仍然可以讀寫其他的Cookie.Cookie


和Session的區別:
1.cookie數據存放在客戶的瀏覽器上,會話數 據放在服務器上;
2.cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙,考慮到安全應當使用會話;
3.session會在一定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能。考慮到減輕服務器性能方面,應當使用COOKIE;
4. 單個cookie在客戶端的限制是3K,就是說一個站點在客戶端存放的COOKIE不能超過3K;


Cookie和Session的方案雖然分別屬於客戶端和服務端,但是服務端的會話的實現對客戶端的cookie的有依賴關係的,上面我講到服務端執行會話機制時候會生成會話的ID值,這個ID值會發送給客戶端,客戶端每次請求都會把這個ID值放到HTTP請求的頭部發送給服務端,而這個ID值在客戶端會保存下來,保存的容器就是餅乾,因此當我們完全禁掉瀏覽器的餅乾的時候,服務端的會話也會不能正常使用(注意:有些資料說ASP解決這個問題,當瀏覽器的cookie的 禁掉,服務端的會話任然可以正常使用,ASP我沒試驗過,但是對於網絡上很多用PHP和JSP編寫的網站,我發現禁掉的cookie,網站的會話都無法正常的訪問)。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章