本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。

Session 是什么

在 Web 应用程序中,Session(会话)是用于在多个请求之间保持用户状态的一种机制。由于 HTTP 协议是无状态的,每个请求都是独立的,服务器无法直接知道两个请求是否来自同一个用户。Session 通过在服务器端存储用户状态信息,并在客户端使用一个唯一的 Session ID 来标识用户,从而实现状态保持。

Session 工作原理如下:

  1. 创建 Session:当用户第一次访问 Web 应用程序时,服务器创建一个新的 Session,并生成一个唯一的 Session ID
  2. 发送 Session ID:服务器将 Session ID 发送给客户端,通常通过 HTTP 响应头中的 Set-Cookie 字段
  3. 存储 Session ID:客户端浏览器将 Session ID 存储在 Cookie 中,并在后续请求中将其发送回服务器
  4. 识别 Session:服务器通过接收到的 Session ID 识别用户的会话,并从服务器端存储中获取相应的 Session 数据

四种主要技术

  1. Cookies
  2. Hidden Form Field
  3. URL Rewriting
  4. HttpSession

1. Cookies(Cookie)

Cookie 是存储在客户端浏览器中的小数据片段。它们会随着每个 HTTP 请求一起发送到服务器,可以用来存储会话标识符。

工作原理

  • 当用户第一次访问网站时,服务器生成一个唯一的会话 ID,并将其作为 Cookie 发送到客户端浏览器
  • 浏览器存储这个 Cookie,并在后续请求中将其发送回服务器
  • 服务器使用 Cookie 中的会话 ID 来检索用户的会话数据

优点

  • 对用户透明
  • 由浏览器自动管理
  • 可以存储少量数据

缺点

  • 用户可以在浏览器中禁用 Cookie
  • 存储容量有限(通常每个 Cookie 大约 4KB)
  • 如果处理不当,可能存在安全问题(例如 Cookie 盗窃)

示例

import javax.servlet.http.Cookie;


// 在Servlet中设置Cookie
Cookie sessionCookie = new Cookie("JSESSIONID", session.getId());
sessionCookie.setMaxAge(30 * 60); // 30分钟
response.addCookie(sessionCookie);

// 在Servlet中检索Cookie
Cookie[] cookies = request.getCookies();  // 从请求获取Cookie
if (cookies != null) {
    for (Cookie cookie : cookies) {
        if ("JSESSIONID".equals(cookie.getName())) {
            String sessionId = cookie.getValue();
            // 使用会话ID检索会话数据
        }
    }
}

Cookie 有两种类型:

  • 非持久性 Cookie(Non-persistent cookie),也称为会话 Cookie(Session cookie),仅在浏览器会话期间有效。当用户关闭浏览器时,这些 Cookie 会被自动删除。适用于需要在用户会话期间保持状态的信息,如购物车内容、临时会话 ID 等。

  • 持久性 Cookie(Persistent cookie),在浏览器会话结束后仍然有效,直到达到指定的过期时间或被用户手动删除。它们存储在客户端的硬盘上。适用于需要在多个会话之间保持状态的信息,如记住用户登录状态、用户偏好设置等。

2. 隐藏表单字段(Hidden Form Field)

隐藏表单字段用于在 HTML 表单中存储会话数据。当表单提交时,这些数据会发送到服务器。

工作原理

  • 服务器生成一个唯一的会话 ID,并将其作为隐藏字段包含在 HTML 表单中
  • 当用户提交表单时,隐藏字段会随表单数据一起发送到服务器
  • 服务器从隐藏字段中检索会话 ID,并使用它来访问用户的会话数据

优点

  • 实现简单
  • 不依赖于浏览器设置(例如 Cookie)

缺点

  • 仅适用于表单提交
  • 需要修改所有表单以包含隐藏字段
  • 不适用于跨多个页面跟踪会话(没有表单的页面)

示例

<form action="submitForm" method="post">
    <input type="hidden" name="sessionId" value="<%= session.getId() %>">
    <!-- 其他表单字段 -->
    <input type="submit" value="提交">
</form>

3. URL 重写(URL Rewriting)

URL 重写涉及将会话 ID 附加到每个请求的 URL 中。这种技术确保会话 ID 随每个请求一起发送到服务器。

工作原理

  • 服务器生成一个唯一的会话 ID,并将其作为查询参数附加到 URL 中
  • 会话 ID 包含在服务器生成的所有后续 URL 中
  • 服务器从 URL 中检索会话 ID,并使用它来访问用户的会话数据

优点

  • 即使禁用 Cookie 也能工作
  • 可以跨多个页面跟踪会话

缺点

  • URL 变得更长且不易读
  • 需要修改所有 URL 以包含会话 ID
  • 如果会话 ID 暴露在 URL 中,可能存在安全风险

示例

// 生成带有会话ID的URL
// http://localhost:8080/myapp/nextPage.jsp;jsessionid=1234567890ABCDEF1234567890ABCDEF
String url = response.encodeURL("nextPage.jsp");

// 从URL中检索会话ID
String sessionId = request.getParameter("jsessionid");

4. HttpSession

HttpSession 接口提供了一种内置的会话跟踪机制。它抽象了底层的会话跟踪技术(例如 Cookie、URL 重写),并提供了一个简单的 API 来管理会话数据。

工作原理

  • 服务器为每个用户会话创建一个 HttpSession 对象
  • 会话 ID 由服务器管理,可以存储在 Cookie 或 URL 中
  • HttpSession 对象提供了存储和检索会话属性的方法

优点

  • 简单且方便的 API
  • 抽象了底层的会话跟踪机制
  • 自动处理会话的创建、过期和失效

缺点

  • 依赖于服务器的会话管理实现
  • 可能需要额外配置以实现会话持久化和集群

示例

// 创建或检索会话
HttpSession session = request.getSession();

// 在会话中存储属性
session.setAttribute("username", "JohnDoe");

// 从会话中检索属性
String username = (String) session.getAttribute("username");

// 使会话失效
session.invalidate();

在多数情况下,使用 HttpSession 是最方便和有效的方法,因为它抽象了底层的会话跟踪机制,并提供了一个简单的 API 来管理会话数据。

为什么 request.getSession()能拿到 session?

HttpSession 抽象了底层的会话跟踪技术,实际上请求的 sessionid 还是通过 cookie 或 url,从客户端发给服务器的,比如 cookie,服务器响应(第一次请求时创建会话):

HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=1234567890ABCDEF1234567890ABCDEF; Path=/; HttpOnly
Content-Type: text/html

客户端请求(后续请求中包含 sessionid):

GET /myapp/urlRewriting HTTP/1.1
Host: example.com
Cookie: JSESSIONID=1234567890ABCDEF1234567890ABCDEF

HttpSession 是一个封装好的接口,提供了一组方法,简化了 Session 管理。

参考资料:

https://www.javatpoint.com/session-tracking-in-servlets

ChatGPT