day21-web開發會話技術03

一刀一個小西瓜發表於2022-11-22

WEB開發會話技術03

10.問題引出

  • 問題引出

    1. 不同的使用者登入網站後,不管該使用者瀏覽網站的哪個頁面,都可以顯示登入人的名字,還可以隨時去檢視自己購物車中的商品,這是如何實現的呢?
    2. 也就是說,一個使用者在瀏覽一個網站的不同頁面時,伺服器是如何知道是張三在瀏覽這個頁面,還是李四在瀏覽這個頁面?
    image-20221122165542791
  • 解決方法1- 使用cookie

    在使用者登入的時候,伺服器可以將使用者資訊透過cookie的形式保留在瀏覽器。每當使用者訪問不同的網頁(傳送HTTP請求),瀏覽器都會將該cookie傳送給伺服器,伺服器透過獲取cookie的值,在網頁上就可以顯示當前使用者的資訊;同時伺服器也可以透過cookie(使用者資訊)找到使用者操作使用者在資料庫中對應的資料。

    但是使用cookie會存在以下問題:第一是cookie不能存放大的資料;第二是cookie不安全,不能存放敏感資訊;第三,cookie不是跟一個使用者關聯的。如果一個cookie是長期儲存的,那麼當其他人開啟瀏覽器時,也可以登入你的賬號,因此單單使用cookie來實現也不太理想。

  • 解決方法2- 使用session

    session是伺服器端的技術,也就是說session的資料是儲存在伺服器端的。伺服器在執行時會為每一個使用者的瀏覽器建立一個其獨享的session物件(該物件可以理解為一個集合)。

    由於session為每個使用者瀏覽器獨享,所以使用者在訪問伺服器的不同頁面時,可以從各自的session中讀取/新增資料,從而完成任務。

11.Session基本介紹

image-20221122170001190 image-20221122170018004

  1. 當使用者開啟瀏覽器,訪問某個網站,操作session時,伺服器就會在記憶體(在服務端)為該瀏覽器分配一個session物件,該session物件被這個瀏覽器獨佔,如上圖

  2. 這個session物件也可以看做是一個容器/集合,session物件預設存在的時間為30min(在tomcat/conf/web.xml中可以修改)

    image-20221122171445199

11.1session可以做什麼

  1. 網上商城的購物車
  2. 儲存登入使用者的資訊
  3. 將資料放入到Session中,供使用者在訪問不同頁面時,實現跨頁面訪問資料
  4. 防止使用者非法登入到某個頁面
  5. .......

11.2如何理解session

  1. session儲存結構示意圖

    image-20221122172136393
  2. 你可以把session看做是一容器(類似HashMap),有兩列(k-v),每一行就是session的一個屬性

  3. 每個屬性包含有兩個部分,一個是該屬性的名字(String),一個是該屬性的值(Object)

12.Session常用方法

  1. 建立和獲取session(api一樣)

    HttpSession session = request.getSession();
    

    第一次呼叫是建立Session會話,之後呼叫是獲取建立好的Session物件

  2. 向session新增屬性

    session.setAttribute(String name,Object val);
    
  3. 從session得到某個屬性

    Object obj = session.getAttribute(String name);
    
  4. 從session刪除某個屬性

    session.removeAttribute(String name);
    
  5. isNew(); 判斷是不是剛建立出來的Session

  6. 每個Session都有一個唯一標識的Id值(即JSESSIONID),透過getId()得到Session的會話Id值

13.Session底層實現機制

13.1原理分析圖

day21-web開發會話技術03 day21-web開發會話技術03

整個過程如下:

一個瀏覽器向伺服器傳送請求,要操作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();
    }
}
  1. 首先訪問http://localhost:8080/cs/createSession:

    image-20221122204458520
  2. 抓包顯示:

    image-20221122210329107

    走的是如下流程:

    image-20221122212119326
  3. 伺服器後端顯示:

    image-20221122210358675
  4. 此時瀏覽器儲存的JSESSIONID變成了新的值:

    image-20221122210627583
  5. 此時,如果再次訪問伺服器,就會攜帶cookie中新的jsessionid給伺服器,伺服器不再返回jsessionid。

    image-20221122211430841

    ​ 走的是如下流程:

    image-20221122212019791
  6. 如果redeployTomcat,關閉瀏覽器並重新開啟,直接訪問http://localhost:8080/cs/createSession,這時候的請求頭將不會攜帶jsessionid(因為關閉瀏覽器時預設刪除了cookie),伺服器返回的響應頭將會攜帶一個jsessionid(因為重新發布tomcat,會清空伺服器記憶體,這時請求的資源createSession程式會建立一個session,因此伺服器會返回一個與之關聯的jsessionid)

    這時候走的就是如下流程:

    image-20221122213113955

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();
    }
}
  1. redeployTomcat,首先在瀏覽器中訪問http://localhost:8080/cs/createSession(目的是建立一個和瀏覽器關聯的session,因為redeployTomcat會刪除伺服器的session)

  2. 然後訪問http://localhost:8080/cs/readSession,並抓包:

    image-20221122215929113
  3. 在伺服器後臺輸出如下:第一行輸出是我們建立session時獲取的sessionid,第二行是我們讀取session時獲取的sessionid,並獲取其屬性。

    image-20221122220217803

14.Session生命週期

  1. public void setMaxInactiveInterval(int interval):設定session的超時時間(以秒為單位),超過指定的時長,session就會被銷燬。

  2. 值為正數的時候,設定session的超時時長。

  3. 值為負數時,表示永不超時

  4. public int getMaxInactiveInterval()表示獲取session的超時時間

  5. public void invalidate()表示讓當前的session會話立即無效

  6. 如果沒有呼叫setMaxInactiveInterval(int interval)來指定session的生命時長,Tomcat會以session的預設時長為準,session的預設時長為30分鐘,可以在tomcat目錄的conf目錄下的web.xml中設定。

    image-20221122222712748
  7. Session的生命週期指的是:客戶端兩次請求的最大間隔時長,而不是累積時長。即當客戶端訪問了自己的session,session的生命週期將將從0開始重新計算。(指的是同一個會話兩次請求之間的間隔時間)

    cookie的生命週期指的是累積時長

  8. 底層:Tomcat用一個執行緒來輪詢會話狀態,如果某個會話的空閒時間超過設定的最大值,則將該會話銷燬。

相關文章