會話狀態管理
HTTP協議是一種無狀態的協議,WEB服務器本身不能識別出哪些請求是同一個瀏覽器發出的,瀏覽器的每一次請求都是完全孤立的。
問題引入:
怎麼才能實現網上購物:某個用戶從網站的登錄頁面登入後,再進入購物頁面購物時,負責處理購物請求的服務器程序必須知道處理上一次請求的程序所得到的用戶信息。
如何解決:
作爲 web 服務器,必須能夠採用一種機制來唯一地標識一個用戶,同時記錄該用戶的狀態,因此web服務器採用一種會話機制來解決這方面的問題。
會話和會話狀態:
Web應用中的會話指一個客戶端瀏覽器與web服務器之間連續發生一系列請求和響應的過程。
Web應用的會話狀態指web服務器與browser在會話過程中產生的狀態信息。藉助會話狀態,web服務器能夠把屬於同一會話的一系列請求和響應過程關聯起來。
如何實現會話:
Web服務器要想從大量請求消息中區分出哪些屬於同一會話的請求消息,即識別來自同一browser的請求,需要browser對其發出的每個請求都進行標識,這個標識號就稱爲會話ID(SessionID)。
在Servlet規範中,常用兩種會話跟蹤機制:
- Cookie
- Session
Cookie機制
cookie使用在客戶端browser保持http狀態信息的機制。
當瀏覽器訪問web服務器資源時,web服務器在傳送http響應消息頭給browser時,在響應頭中附加一個小文本文件,這個小文本文件中存儲的就是cookie的相關信息。
browser會保存cookie的信息,一旦browser保存某個cookie,那麼在以後訪問該web服務器時,都會在http請求消息頭中將這個cookie的信息傳給web服務器。
底層實現:WEB服務器通過在HTTP響應消息中增加Set-Cookie響應頭字段將Cookie信息發送給瀏覽器,瀏覽器則通過在HTTP請求消息中增加Cookie請求頭字段將Cookie回傳給WEB服務器。
- 一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和值(VALUE)。
- 一個WEB站點可以給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也可以存儲多個WEB站點提供的Cookie。
- 瀏覽器一般只允許存放300個Cookie,其中允許每個站點最多20個Cookie,每個Cookie的大小限制爲4KB。
Cookie傳送過程示意圖
Servlet中使用Cookie:
Servlet API中提供了一個javax.servlet.http.Cookie類來封裝Cookie信息,它包含有生成Cookie信息和提取Cookie信息的各個屬性的方法。
Cookie類的方法:
public Cookie(String name,String value) 構造方法,value不能爲中文.
getName()方法
setValue()與getValue()方法
setMaxAge()與getMaxAge()方法 (用來設置Cookie的時效,即過期時間)
setPath()與getPath()方法
使用Cookie的流程:
- 如果創建一個cookie,並將它發送到瀏覽器,默認下它是一個會話級別的cookie(另一個是持久級別的Cookie,下面介紹),存儲在瀏覽器的內存中,用戶退出瀏覽器之後被刪除。
- 若希望瀏覽器將該cookie存儲在磁盤上,則需要使用Cookie的setMaxAge(),並給出一個以秒爲單位的時間。將最大時效設爲0則是命令瀏覽器刪除該cookie。
- 發送cookie需要使用HttpServletResponse的addCookie()方法,將cookie插入到一個 Set-Cookie HTTP響應報頭中。這個方法並不修改任何之前指定的Set-Cookie報頭,而是創建新的報頭。
- HttpServletRequest接口中定義了一個getCookies()方法,它用於從HTTP請求消息的Cookie請求頭字段中讀取所有的Cookie項,返回Cookie數組。
- 會話Cookie,不設置cookie的過期時間,只要瀏覽器關閉,cookie就消失,生命週期爲瀏覽器會話期的Cookie稱爲會話Cookie。一般保存在內存而非磁盤中。
- 持久Cookie,設置過期時間,瀏覽器就會把cookie保存在磁盤上,關閉瀏覽器後再次打開,這些cookie仍有效,除非超過設定的過期時間。同時存儲在硬盤上的cookie能被不同瀏覽器進程共享。
Session機制
session使用的是在服務器端保持http狀態信息的機制。
當服務端需要爲某個客戶端的請求創建一個session時,服務器首先檢查這個客戶端的請求裏是否包含了一個session標識(即JSESSIONID)
如果已經包含一個JSESSIONID則說明以前已經爲此客戶創建過session,服務器就按照JSESSIONID把這個session檢索出來使用。
如果客戶請求不包含JSESSIONID,則爲此客戶創建一個session並且生成一個與此session相關聯的JSESSIONID,這個JSESSIONID將在本次響應中返回給客戶端保存。
過程示意圖:
底層實現:
1. 當用戶第一次使用session時(表示第一次請求服務器),服務器會創建session,
並創建一個Cookie,在Cookie中保存session的id,發送給客戶端,這樣客戶端就有了自己session的id了。但這個Cookie只在瀏覽器內存中存在,也就是說,在關閉瀏覽器窗口後,Cookie就會丟失,也就丟失了sessionId。
2. 當用戶第二次訪問服務器時,會在請求中把保存sessionId的Cookie發送給服務器,服務器通過sessionId查找session對象,然後使用。也就是說,只要瀏覽器不關閉,無論訪問服務器多少次,使用的都是同一個session對象。這樣也就可以讓多個請求共享同一個session。
3. 當用戶關閉瀏覽器窗口,再打開瀏覽器訪問服務器時,這時請求中已沒有sessionId。那麼服務器會創建一個session,再把sessionId通過Cookie保存到瀏覽器中,這時一個新的會話開始了,原來的session會因關閉瀏覽器而失效。
4. 當用戶打開某個服務器頁面長時間沒動作時,這樣session會超時失效,當用戶再有活動時,服務器通過用戶提供的sessionId已找不到session對象。那麼服務器還是會創建一個新的session對象,再把新的sessionId保存到客戶端,一個新的會話又開始了。
session的創建
是在服務端程序(如Servlet)調用HttpServletRequest.getSession(true)或者HttpServletRequest.getSession()時,而非在客戶端訪問時被創建。
getSession():如果當前已經創建session對象,則直接返回這個sessoin對象;如果沒有則創建一個新的。
getSession(true);如果不存在會話就創建一個新的會話(如果想把數據寫入到會話中)
getSession(false):如果不存在會話就返回null(如果只是想讀取會話中的數據)
當向Session中存取登錄信息時,一般建議:HttpSession session =request.getSession();
當從Session中獲取登錄信息時,一般建議:HttpSession session =request.getSession(false);
session的刪除:
- 程序調用HttpSession.invalidate()
- 距離上一次收到客戶端發送的session id時間間隔超過了session的最大有效時間(tomcat服務器默認30分鐘)
- 服務器進程被停止
注意:關閉瀏覽器只會使存儲在客戶端瀏覽器內存中的session cookie失效,不會使服務器端的session對象失效。
session的超時管理:
- WEB服務器採用“超時限制”的辦法來判斷客戶端是否還在繼續訪問,如果某個客戶端在一定的時間內沒有發出後續請求,WEB服務器則認爲客戶端已經停止活動,結束與該客戶端的會話並將與之對應的HttpSession對象變成垃圾。
- 如果客戶端瀏覽器超時後再次發出訪問請求,WEB服務器則認爲這是一個新會話的開始,將爲之創建新的HttpSession對象和分配新的會話標識號。
- 會話超時時間間隔可在web.xml中設置,默認值(30min)由Servlet容器定義.
<session-config>
<session-timeout>30</session-timeout>
</session-config>
HttpSession接口中的方法:
- getId方法
- getCreationTime方法
- getLastAccessedTime方法
- setMaxInactiveInterval方法
- getMaxInactiveInterval方法
- isNew方法
- invalidate方法
- getServletContext方法
- setAttribute方法
- getAttribute方法
- removeAttribute方法
- getAttributeNames方法
HttpServletRequest接口中的Session方法:
- getSession方法 (之前已經介紹)
public HttpSession getSession(boolean create)
public HttpSession getSession()
- isRequestedSessionIdValid方法 --請求session是否有效
- isRequestedSessionIdFromCookie方法 --請求session是否來自cookie
- isRequestedSessionIdFromURL方法 --請求session是否來自url
瀏覽器訪問服務端的任何一個 JSP 或 Servlet,是否都會立即創建一個 HttpSession
- 若當前的 JSP(或 Servlet) 是客戶端訪問的當前 WEB 應用的第一個資源,且 JSP 的 page 指定的 session 屬性值爲 false, 則服務器就不會爲 JSP 創建一個 HttpSession 對象;
- 若當前 JSP 不是客戶端訪問的當前 WEB 應用的第一個資源,且其他頁面已經創建一個 HttpSession 對象,則當前 JSP 頁面會返回一個會話的 HttpSession 對象,而不會創建新的 HttpSession對象。
- 對於 Serlvet 而言:若 Serlvet 是客戶端訪問的第一個 WEB 應用的資源,則只有調用了 request.getSession() 或 request.getSession(true) 纔會創建 HttpSession 對象。