WEB開發會話技術03
10.問題引出
-
問題引出
- 不同的使用者登入網站後,不管該使用者瀏覽網站的哪個頁面,都可以顯示登入人的名字,還可以隨時去檢視自己購物車中的商品,這是如何實現的呢?
- 也就是說,一個使用者在瀏覽一個網站的不同頁面時,伺服器是如何知道是張三在瀏覽這個頁面,還是李四在瀏覽這個頁面?
-
解決方法1- 使用cookie
在使用者登入的時候,伺服器可以將使用者資訊透過cookie的形式保留在瀏覽器。每當使用者訪問不同的網頁(傳送HTTP請求),瀏覽器都會將該cookie傳送給伺服器,伺服器透過獲取cookie的值,在網頁上就可以顯示當前使用者的資訊;同時伺服器也可以透過cookie(使用者資訊)找到使用者操作使用者在資料庫中對應的資料。
但是使用cookie會存在以下問題:第一是cookie不能存放大的資料;第二是cookie不安全,不能存放敏感資訊;第三,cookie不是跟一個使用者關聯的。如果一個cookie是長期儲存的,那麼當其他人開啟瀏覽器時,也可以登入你的賬號,因此單單使用cookie來實現也不太理想。
-
解決方法2- 使用session
session是伺服器端的技術,也就是說session的資料是儲存在伺服器端的。伺服器在執行時會為每一個使用者的瀏覽器建立一個其獨享的session物件(該物件可以理解為一個集合)。
由於session為每個使用者瀏覽器獨享,所以使用者在訪問伺服器的不同頁面時,可以從各自的session中讀取/新增資料,從而完成任務。
11.Session基本介紹
-
當使用者開啟瀏覽器,訪問某個網站,操作session時,伺服器就會在記憶體(在服務端)為該瀏覽器分配一個session物件,該session物件被這個瀏覽器獨佔,如上圖
-
這個session物件也可以看做是一個容器/集合,session物件預設存在的時間為30min(在tomcat/conf/web.xml中可以修改)
11.1session可以做什麼
- 網上商城的購物車
- 儲存登入使用者的資訊
- 將資料放入到Session中,供使用者在訪問不同頁面時,實現跨頁面訪問資料
- 防止使用者非法登入到某個頁面
- .......
11.2如何理解session
-
session儲存結構示意圖
-
你可以把session看做是一容器(類似HashMap),有兩列(k-v),每一行就是session的一個屬性
-
每個屬性包含有兩個部分,一個是該屬性的名字(String),一個是該屬性的值(Object)
12.Session常用方法
-
建立和獲取session(api一樣)
HttpSession session = request.getSession();
第一次呼叫是建立Session會話,之後呼叫是獲取建立好的Session物件
-
向session新增屬性
session.setAttribute(String name,Object val);
-
從session得到某個屬性
Object obj = session.getAttribute(String name);
-
從session刪除某個屬性
session.removeAttribute(String name);
-
isNew(); 判斷是不是剛建立出來的Session
-
每個Session都有一個唯一標識的Id值(即JSESSIONID),透過getId()得到Session的會話Id值
13.Session底層實現機制
13.1原理分析圖
整個過程如下:
一個瀏覽器向伺服器傳送請求,要操作session時,一定會呼叫request.getSession()方法。
- 這個方法會先判斷瀏覽器是否攜帶了JSESSIONID的cookie:
- 如果沒有攜帶,就會在伺服器記憶體中建立一個session物件,並且為這個session分配一個sessionId。如上圖,可以理解為伺服器記憶體有一個map<String,Object>,sessionId作為map的key,session物件作為key關聯的value。如此,這個sessionId就和該session物件關聯起來了。
- 如果攜帶了,就會進一步判斷:判斷服務端的map中是否已經存在了該JSESSIONID對應的session物件
- 如果map中沒有,就會建立一個session物件,並且為這個session分配一個新的sessionId。
- 如果map中已經存在了該JSESSIONID對應的session物件,就直接操作。
如果伺服器在本次會話中,建立了session,則在響應頭中將以Set-Cookie:JSESSIONID=xxxx
的形式返回一個cookie給瀏覽器儲存。下一次瀏覽器傳送請求時,伺服器就可以拿到cookie中的JSESSIONID的值,在map中找到該瀏覽器對應的session,直接操作。
這裡的map可以理解為在Tomcat中還維護了一個容器HashMap<String,HttpSession>,這個容器中以JSESSIONID為key,以session為value,完成兩者的繫結。
13.2程式碼演示
演示Session底層實現機制-建立和讀取Session
13.2.1建立session的例項分析
web.xml:
<servlet>
<servlet-name>CreateSession</servlet-name>
<servlet-class>com.li.session.CreateSession</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CreateSession</servlet-name>
<url-pattern>/createSession</url-pattern>
</servlet-mapping>
CreateSession:
package com.li.session;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class CreateSession extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//System.out.println("CreateSession doPost被呼叫...");
//1.獲取session(同時也可能建立session)
HttpSession session = request.getSession();//注意這個地方已經把sessionId分配了
//2.給session獲取id
System.out.println("當前sessionid= " + session.getId());
//3.給session存放一些資料
session.setAttribute("email", "zs@qq.com");
//4.給瀏覽器傳送一個回覆
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<h1>建立/操作session成功...</h1>");
writer.flush();
writer.close();
}
}
-
首先訪問
http://localhost:8080/cs/createSession
: -
抓包顯示:
走的是如下流程:
-
伺服器後端顯示:
-
此時瀏覽器儲存的JSESSIONID變成了新的值:
-
此時,如果再次訪問伺服器,就會攜帶cookie中新的jsessionid給伺服器,伺服器不再返回jsessionid。
走的是如下流程:
-
如果redeployTomcat,關閉瀏覽器並重新開啟,直接訪問
http://localhost:8080/cs/createSession
,這時候的請求頭將不會攜帶jsessionid(因為關閉瀏覽器時預設刪除了cookie),伺服器返回的響應頭將會攜帶一個jsessionid(因為重新發布tomcat,會清空伺服器記憶體,這時請求的資源createSession程式會建立一個session,因此伺服器會返回一個與之關聯的jsessionid)這時候走的就是如下流程:
13.2.2讀取session的例項分析
web.xml:
<servlet>
<servlet-name>ReadSession</servlet-name>
<servlet-class>com.li.session.ReadSession</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ReadSession</servlet-name>
<url-pattern>/readSession</url-pattern>
</servlet-mapping>
ReadSession:
package com.li.session;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class ReadSession extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//System.out.println("ReadSession doPost被呼叫...");
//演示讀取session
//1.獲取session,如果沒有session也會建立
HttpSession session = request.getSession();
//2.給session獲取id
System.out.println("ReadSession 當前sessionid= " + session.getId());
//3.讀取屬性
Object email = session.getAttribute("email");
if (email != null) {
System.out.println("session屬性 email= " + (String) email);
} else {
System.out.println("session中沒有 email屬性");
}
//3.給瀏覽器傳送一個回覆
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<h1>讀取session成功...</h1>");
writer.flush();
writer.close();
}
}
-
redeployTomcat,首先在瀏覽器中訪問
http://localhost:8080/cs/createSession
(目的是建立一個和瀏覽器關聯的session,因為redeployTomcat會刪除伺服器的session) -
然後訪問
http://localhost:8080/cs/readSession
,並抓包: -
在伺服器後臺輸出如下:第一行輸出是我們建立session時獲取的sessionid,第二行是我們讀取session時獲取的sessionid,並獲取其屬性。
14.Session生命週期
-
public void setMaxInactiveInterval(int interval)
:設定session的超時時間(以秒為單位),超過指定的時長,session就會被銷燬。 -
值為正數的時候,設定session的超時時長。
-
值為負數時,表示永不超時
-
public int getMaxInactiveInterval()
表示獲取session的超時時間 -
public void invalidate()
表示讓當前的session會話立即無效 -
如果沒有呼叫
setMaxInactiveInterval(int interval)
來指定session的生命時長,Tomcat會以session的預設時長為準,session的預設時長為30分鐘,可以在tomcat目錄的conf目錄下的web.xml中設定。 -
Session的生命週期指的是:客戶端兩次請求的最大間隔時長,而不是累積時長。即當客戶端訪問了自己的session,session的生命週期將將從0開始重新計算。(指的是同一個會話兩次請求之間的間隔時間)
cookie的生命週期指的是累積時長
-
底層:Tomcat用一個執行緒來輪詢會話狀態,如果某個會話的空閒時間超過設定的最大值,則將該會話銷燬。