1. 程式人生 > >Servlet學習筆記(七):Session詳解

Servlet學習筆記(七):Session詳解

Session是伺服器端技術,伺服器在執行時可以為每個使用者的瀏覽器建立一個其獨享的Session物件,由於Session為使用者瀏覽器獨享,所以使用者在訪問伺服器的web資源時,可以把各自的資源放在各自的Session中,當用戶再去訪問伺服器中的其他web資源時,其他web資源再從使用者各自的Session中取出資料為使用者服務。

一、Session基礎知識

1、工作原理:

Cookie類似於檢查客戶身上的“通行證”來確定客戶身份的話,那麼 Session 機制就是通過檢查伺服器上的“客戶明細表”來確認客戶身份。Session相當於程式在伺服器上建立的一份客戶檔案,客戶來訪的時候只需要查詢客戶檔案表就可以了。

2、實現方式。

1)通過 Cookie 實現——將Session的 ID 放入 Cookie。

A、Session 的實現需要使用Cookie作為識別標誌。Session 不能依據 HTTP 連線判斷是否為同一個客戶,因此伺服器向客戶端傳送一個名為JSESSIONID的 Cookie ,它的值為該Session的ID。Sessin依據該Cookie來識別是否為同一使用者。

這邊的JSESSIONID只是個名字,可以隨便修改的。配置伺服器的<Context  sessionCookieName=" XXX ">設定。

B、該Cookie 為伺服器自動生成的,它的 maxAge屬性一般為 -1,表示僅當前瀏覽器內有效(包括字視窗),關閉瀏覽器失效,各瀏覽器不共享。

這會是一個問題,當你關閉瀏覽器,在重開,就會是另一個Cookie。解決辦法:伺服器在建立Session的時候回寫一個同名的Cookie,並設定maxAge值即可,注意有path(見下圖)

		// 解決自動生成的cookie為臨時性問題,回寫一個同名Cookie回去
		Cookie cookie = new Cookie("JSESSIONID",session.getId());		
		cookie.setMaxAge(session.getMaxInactiveInterval());
		cookie.setPath(this.getServletContext().getContextPath());
		response.addCookie(cookie);


C、注意:第一次訪問的時候,因為JSESSIONID是放在Cookie中,伴隨瀏覽器訪問傳入,所以第一次訪問的時候是沒有的。request.getRequestedSessionId() 返回為空。這點在Firefox試驗是沒問題的。但是Chrome中會有出入。

Firefox在第一次訪問的時候,請求資訊中是沒有 JSESSIONID資料的,請求結束,伺服器返回。如下:


但是,Chrome在第一次訪問的時候,請求中即會有一個臨時的JSESSIONID,然後返回一個。如下:


問題:

有一種解釋為:第一次訪問的時候,在你的程式第一次訪問伺服器的時候,服務端並不知道你的客戶端瀏覽器是否支援cookie,因此,當你第一次請求發起的時候,服務端會預設url重寫,也就是將session id寫到url中傳遞。

或者只是瀏覽器的支援問題?暫時沒解決。

2)通過URL 重寫實現——將Session的 ID 重寫到URL地址中。

A、針對客戶端不支援Cookie的情況,可以通過 URL 重寫實現Session 。

B、response.encodeURL(String url)實現 URL 地址的重寫。如果重定向可以這麼寫:response.sendRedirect(response.encodeRedirectURL("/"))

		// 通過 重寫URL實現
		response.encodeURL("/");
		response.encodeRedirectURL("/");
		response.sendRedirect(response.encodeRedirectURL("/"));


C、可以在伺服器配置,取消重寫的功能。配置Tomcat 的<Context  disableURLRewriting="true">即可。

3、Session 的 建立

封裝在javax.servlet.http.HttpSession 物件中,可以通過request.getSession()獲取。

		HttpSession session = request.getSession();//不存在,返回空
		HttpSession session = request.getSession(true);//不存在,新建一個

4、Session 的ID。

String sessionId = session.getId();

5、Session 的時間。

1)有效期。

		// 3-1 有效期
		// get/set MaxInactiveInterval可以設定和獲取session的有效期  單位為 秒
		// 也可以通過 <session-config>標籤配置在web.xml中 ,單位為分鐘
		// tomcat自身的config/web.xml 預設配置session有效期為 30 分鐘
		// 如通過setMaxInactiveInterval設定過有效時間,這段程式碼注掉,時間還是不會改變。
		
		session.setMaxInactiveInterval(1000 * 5);
		int time = session.getMaxInactiveInterval();


2)建立時間。

		// 3-2 建立時間
		long createTime = session.getCreationTime();//返回long
		Date createDate = new Date(createTime);
		logger.debug("Session建立的時間為 : " + formatDate(createDate));

3)最近訪問時間。

		
		// 3-3 最近訪問時間
		// 客戶端只要訪問伺服器,不管有沒有讀寫session,伺服器都會更新最近訪問時間,並維護本session
		long accessedTime = session.getLastAccessedTime();//返回long
		Date accessedDate = new Date(accessedTime);
		logger.debug("Session最近訪問的時間為 : " + formatDate(accessedDate));


6、Session路徑

Session 在客戶端對應同一個視窗,沒有路徑訪問問題,同一個servletContext 下的servlet/jsp共享同一個Session 。前提是同一個客戶端視窗。

二、Session 的生命週期

1)Session在使用者第一次訪問伺服器的時候自動建立。只有訪問JSP、Servlet等程式才會建立Session(是訪問到getSession()程式碼時), 只訪問 HTML、 等靜態資源並不會建立Session。 如果尚未生成Session ,也可以使用request.getSession(true)強制生成。

2)Session生成後,只要使用者繼續訪問,伺服器就會更新Session 的最後訪問時間,並維護該 Session 。使用者每訪問伺服器一次,無論是否讀寫 Session ,伺服器都認為該使用者的 Session “活躍(active)”了一次。

3)關閉瀏覽器,不會讓 Session 結束,Session 是伺服器管理的,只有當 session.invalidate() 程式碼或者配置好的有效時間<session-comfig>到了,Session 才會結束。

三、Session的常用方法。


四、測試程式碼如下:

package servlet.session;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
/**
 * 
 * BaseSession.java
 *
 * @title Session
 * @description
 * @author SAM-SHO 
 * @Date 2014-10-12
 */
public class BaseSession extends HttpServlet {

	private static final long serialVersionUID = 1L;
	
	private Logger logger = Logger.getLogger(this.getClass());


	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}


	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		//  
		boolean isValid = request.isRequestedSessionIdValid();
		logger.debug("請求帶過來的session是否有效 : " + isValid);
		
		// 第一次訪問的時候 firefox 為空,而chrome 確是有值的,但是和下面建立的session不是同一個
		String seesionId = request.getRequestedSessionId();
		logger.debug("request獲取的SessionID : " + seesionId);
		
		boolean isFromCookie = request.isRequestedSessionIdFromCookie();
		boolean isFromUrl = request.isRequestedSessionIdFromURL();
		logger.debug("是否是通過Cookie實現: "  + isFromCookie + " | 是否是通過URL實現: " + isFromUrl);

		
		
		// 1-Session的建立
//		HttpSession session = request.getSession();//不存在,返回空
		HttpSession session = request.getSession(true);//不存在,新建一個
		
		logger.debug("獲取到的Session 為 : " + session.getClass().getName());
		
		// 2-Session的ID
		String sessionId = session.getId();
		logger.debug("建立的 Session的ID 為 : " + sessionId);
		
		// 3-session的時間:三個時間構成了session 的生命週期
		
		// 3-1 有效期
		// get/set MaxInactiveInterval可以設定和獲取session的有效期  單位為 秒
		// 也可以通過 <session-config>標籤配置在web.xml中 ,單位為分鐘
		// tomcat自身的config/web.xml 預設配置session有效期為 30 分鐘
		// 如通過setMaxInactiveInterval設定過有效時間,這段程式碼注掉,時間還是不會改變。
		
		session.setMaxInactiveInterval(1000 * 5);
		int time = session.getMaxInactiveInterval();
		logger.debug("Session的有效期 為 : " + time);
		
		
		// 3-2 建立時間
		long createTime = session.getCreationTime();//返回long
		Date createDate = new Date(createTime);
		logger.debug("Session建立的時間為 : " + formatDate(createDate));
		
		// 3-3 最近訪問時間
		// 客戶端只要訪問伺服器,不管有沒有讀寫session,伺服器都會更新最近訪問時間,並維護本session
		long accessedTime = session.getLastAccessedTime();//返回long
		Date accessedDate = new Date(accessedTime);
		logger.debug("Session最近訪問的時間為 : " + formatDate(accessedDate));
		
		
		// 4-常用方法
		
		// 4-1設定 Attribute 是key-value型別
		// key為String 型別, value為 Object 。可以放置javaBean。比Cookie強大。
		
		session.setAttribute("userName", "Sam-Sho");
		String userName = (String) session.getAttribute("userName");		
		logger.debug("Session中放置的資料   : " + userName);
		
		session.removeAttribute("userName");
		
		// 4-2 讓session失效
		session.invalidate();

		
		// 4-3 其他與session有關的一些方法		
		String seesionId2 = request.getRequestedSessionId();//
		logger.debug("request獲取的SessionID 2: " + seesionId2);
		
		boolean isFromCookie2 = request.isRequestedSessionIdFromCookie();
		boolean isFromUrl2 = request.isRequestedSessionIdFromURL();
		logger.debug("是否是通過Cookie實現2: "  + isFromCookie2 + " | 是否是通過URL實現2: " + isFromUrl2);

//		// 通過 重寫URL實現
//		response.encodeURL("/");
//		response.encodeRedirectURL("/");
//		response.sendRedirect(response.encodeRedirectURL("/"));


	}
	
	/**
	 * 簡單轉換時間
	 * @param date
	 * @return
	 */
	private String formatDate(Date date){
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String strDate = format.format(date);		
		return strDate;
		
	}

}
【輸出】
[JavaWeb] [2014-10-12 11:54:08,345] [DEBUG] [MyFilter:40] - 上下文路徑:/JavaWeb
[JavaWeb] [2014-10-12 11:54:08,345] [DEBUG] [MyFilter:41] - 訪問的servlet或者jsp的路徑 : /servlet/BaseSession
[JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:31] - 請求帶過來的session是否有效 : false
[JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:35] - request獲取的SessionID : 9B582560CB3588E3205030C0B9A9E1D7
[JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:39] - 是否是通過Cookie實現: true | 是否是通過URL實現: false
[JavaWeb] [2014-10-12 11:54:08,361] [DEBUG] [BaseSession:47] - 獲取到的Session 為 : org.apache.catalina.session.StandardSessionFacade
[JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:51] - 建立的 Session的ID 為 : 95698550D17BB0465D6EC43179A984DB
[JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:63] - Session的有效期 為 : 1200
[JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:69] - Session建立的時間為 : 2014-10-12 11:54:08
[JavaWeb] [2014-10-12 11:54:08,365] [DEBUG] [BaseSession:75] - Session最近訪問的時間為 : 2014-10-12 11:54:08
[JavaWeb] [2014-10-12 11:54:08,367] [DEBUG] [BaseSession:85] - Session中放置的資料   : Sam-Sho
[JavaWeb] [2014-10-12 11:54:08,389] [DEBUG] [BaseSession:96] - request獲取的SessionID 2: 9B582560CB3588E3205030C0B9A9E1D7
[JavaWeb] [2014-10-12 11:54:08,389] [DEBUG] [BaseSession:100] - 是否是通過Cookie實現2: true | 是否是通過URL實現2: false


五、Session 和 Cookie 的比較。

1、從存取方式上比較:

1)Cookie 中只能存ASCII字串,其他需要編碼。不能直接存 java 物件。

2)Session 中可以存取任何型別的資料,直接儲存JavaBean。

2、從隱私安全上比較

1)Cookie儲存在客戶端,會存在風險。所以一般一些敏感資訊,如密碼等儘量不要放入 Cookie,並且對Cookie 資訊加密。提交到伺服器在解密,保證安全性。

2)Session 儲存在伺服器,安全多了。

3、從有效期上比較

1)Cookie 的有效期只要設定Cookie 的maxAge即可。

2)Session 如果設定的有效期過長,會導致伺服器累計的 Session 過多,導致記憶體溢位。

4、從對伺服器負擔上比較

1)Cookie無負擔,所以比如大型的網站,電商等都會使用Cookie 追蹤客戶會話。

2)Session 過多就會影響伺服器了。