本文收录于「Java 学习日记」专栏,聚焦 Java Web 会话管理核心,拆解 Cookie 与 Session 的底层原理、使用场景和实战技巧,帮你彻底搞懂 "登录状态怎么保持"~
一、为什么需要会话管理?
在上一篇 Servlet 的学习中,我们知道 HTTP 协议是无状态的 ------ 服务器不会记住每一次请求的客户端身份。比如:
- 你第一次请求 "登录接口",输入账号密码登录成功;
- 第二次请求 "个人中心接口",服务器根本不知道你是谁,会要求你重新登录。
这显然不符合实际需求,而会话管理(Cookie + Session) 就是解决这个问题的核心方案:
- 会话(Session):服务器为每个客户端创建的 "身份标识",记录客户端的登录状态、个性化配置等;
- Cookie:客户端(浏览器)存储的小型文本文件,用于携带会话标识,让服务器识别 "你是谁"。
简单来说:Cookie 是 "客户端身份证",Session 是 "服务器的身份档案",两者配合实现登录状态保持。
二、核心概念:Cookie 与 Session 的本质
1. Cookie:客户端的 "小本本"
Cookie 是服务器发送给客户端的小型文本数据,存储在浏览器中,核心特点:
- 存储位置:客户端(浏览器),可分为 "内存 Cookie"(会话级,关闭浏览器失效)和 "硬盘 Cookie"(持久化,设置过期时间);
- 大小限制:单个 Cookie 最大约 4KB,数量有限(一般每个域名最多 20 个);
- 数据格式:键值对(key=value),可设置过期时间、作用路径、域名等;
- 安全性:明文传输(HTTPS 可加密),不要存储密码、Token 等敏感信息。
2. Session:服务器的 "身份档案"
Session 是服务器为每个客户端创建的内存对象(也可持久化到 Redis / 数据库),核心特点:
- 存储位置:服务器端,安全性更高;
- 数据结构:键值对(可存储任意 Java 对象,无大小限制);
- 关联方式:通过 Cookie 中的
JSESSIONID(会话 ID)关联客户端和服务器的 Session; - 失效机制:默认超时失效(Tomcat 默认 30 分钟),也可手动销毁。
3. Cookie vs Session 核心对比
| 特性 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务器端 |
| 安全性 | 较低(明文) | 较高(服务器内部) |
| 数据大小 | 有限(4KB) | 无限制(受服务器内存影响) |
| 存储内容 | 简单字符串 | 任意 Java 对象 |
| 过期方式 | 可设置过期时间(持久化) | 默认超时失效(Tomcat 30 分钟) |
| 性能影响 | 减轻服务器压力 | 占用服务器内存,高并发需优化 |
三、实战 1:Cookie 的创建、读取与销毁
1. 创建并发送 Cookie 到客户端
编写CookieServlet.java,向客户端发送 Cookie:
java
运行
java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/cookie/demo")
public class CookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 创建Cookie(键值对)
Cookie usernameCookie = new Cookie("username", "Java日记");
Cookie ageCookie = new Cookie("age", "18");
// 2. 设置Cookie过期时间(可选,单位:秒)
// 正数:持久化到硬盘,过期时间后失效;0:立即失效;负数:会话级Cookie(默认)
usernameCookie.setMaxAge(24 * 60 * 60); // 1天过期
ageCookie.setMaxAge(-1); // 会话级,关闭浏览器失效
// 3. 设置Cookie作用路径(可选,默认当前项目路径)
usernameCookie.setPath(request.getContextPath()); // /demo
// 4. 发送Cookie到客户端(必须通过response添加)
response.addCookie(usernameCookie);
response.addCookie(ageCookie);
// 响应提示
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("✅ Cookie已发送到客户端!");
}
}
2. 读取客户端携带的 Cookie
新增方法读取 Cookie:
java
运行
java
@WebServlet("/cookie/read")
public class CookieReadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取客户端所有Cookie
Cookie[] cookies = request.getCookies();
// 2. 遍历Cookie(注意:cookies可能为null)
response.setContentType("text/html;charset=UTF-8");
if (cookies != null) {
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
response.getWriter().write("Cookie名称:" + name + ",值:" + value + "<br>");
}
} else {
response.getWriter().write("❌ 客户端未携带Cookie!");
}
}
}
3. 销毁 Cookie(设置过期时间为 0)
java
运行
java
@WebServlet("/cookie/delete")
public class CookieDeleteServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 销毁Cookie的核心:创建同名Cookie,设置maxAge=0,重新发送
Cookie usernameCookie = new Cookie("username", "");
usernameCookie.setMaxAge(0); // 立即失效
usernameCookie.setPath(request.getContextPath()); // 路径必须和创建时一致
response.addCookie(usernameCookie);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("✅ Cookie已销毁!");
}
}
4. 测试步骤
- 启动 Tomcat,访问
http://localhost:8080/demo/cookie/demo(发送 Cookie); - 访问
http://localhost:8080/demo/cookie/read(读取 Cookie); - 访问
http://localhost:8080/demo/cookie/delete(销毁 Cookie); - 再次访问
/cookie/read,确认usernameCookie 已消失。
四、实战 2:Session 的创建、存取与销毁(登录状态保持)
1. 登录接口:创建 Session 并存储用户信息
java
运行
java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/user/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 解决POST请求中文乱码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 2. 获取登录参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 3. 模拟登录校验(实际项目中查数据库)
if ("admin".equals(username) && "123456".equals(password)) {
// 4. 创建/获取Session(request.getSession():没有则创建,有则返回)
HttpSession session = request.getSession();
// 5. 存储用户信息到Session
session.setAttribute("loginUser", username);
session.setAttribute("userId", 1001);
// 6. 设置Session超时时间(可选,单位:秒,优先级高于Tomcat默认配置)
session.setMaxInactiveInterval(30 * 60); // 30分钟超时
// 7. 获取SessionID(自动通过JSESSIONID Cookie发送到客户端)
String sessionId = session.getId();
response.getWriter().write("🎉 登录成功!SessionID:" + sessionId);
} else {
response.getWriter().write("❌ 用户名或密码错误!");
}
}
}
2. 个人中心接口:读取 Session 验证登录状态
java
运行
java
@WebServlet("/user/center")
public class UserCenterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// 1. 获取Session(false:没有则返回null,不创建新Session)
HttpSession session = request.getSession(false);
// 2. 验证Session是否存在,且用户已登录
if (session != null && session.getAttribute("loginUser") != null) {
String username = (String) session.getAttribute("loginUser");
Integer userId = (Integer) session.getAttribute("userId");
response.getWriter().write("👋 欢迎你," + username + "!用户ID:" + userId);
} else {
// 3. 未登录,重定向到登录页(或提示登录)
response.sendRedirect("/demo/user/login.html");
}
}
}
3. 退出登录接口:销毁 Session
java
运行
java
@WebServlet("/user/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取Session
HttpSession session = request.getSession(false);
// 2. 销毁Session(删除所有属性,并使Session失效)
if (session != null) {
session.invalidate();
}
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("✅ 退出登录成功!");
}
}
4. 测试准备:登录页面(login.html)
在webapps/demo目录下创建login.html:
html
预览
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/demo/user/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
5. 测试步骤
- 访问
http://localhost:8080/demo/login.html,输入admin/123456登录; - 访问
http://localhost:8080/demo/user/center,能看到欢迎信息(登录状态保持); - 访问
http://localhost:8080/demo/user/logout退出登录; - 再次访问
/user/center,会重定向到登录页(登录状态失效)。
五、核心细节:Session 的 JSESSIONID Cookie
- 当调用
request.getSession()时,Tomcat 会自动创建JSESSIONIDCookie,发送到客户端; - 客户端后续请求会携带
JSESSIONID,Tomcat 通过这个 ID 找到对应的 Session; - 若客户端禁用 Cookie,Session 会失效(可通过 URL 重写
response.encodeURL()解决,进阶内容)。
修改UserCenterServlet,演示 URL 重写(兼容禁用 Cookie 的场景):
java
运行
java
// 在/user/center接口中添加URL重写示例
String url = response.encodeURL("/demo/user/center");
response.getWriter().write("<br>URL重写后:" + url);
六、避坑指南:Cookie/Session 常见问题
-
Cookie 中文乱码 :Cookie 不支持中文,存储前需编码(URLEncoder),读取后解码(URLDecoder):
java
运行
java// 存储中文Cookie String value = URLEncoder.encode("Java日记", "UTF-8"); Cookie cookie = new Cookie("nickname", value); // 读取中文Cookie String value = URLDecoder.decode(cookie.getValue(), "UTF-8"); -
Session 失效过快 :
- 检查 Tomcat 默认超时配置(
conf/web.xml中<session-config>,默认 30 分钟); - 代码中通过
session.setMaxInactiveInterval()手动设置超时时间;
- 检查 Tomcat 默认超时配置(
-
Session 共享问题:分布式项目中,单机 Session 无法共享,需用 Redis 存储 Session(进阶内容);
-
Cookie 跨域问题 :Cookie 默认只在当前域名生效,跨域请求需配置
SameSite=None; Secure(HTTPS 环境)。
七、今日实战小任务
- 编写 Servlet,向客户端发送包含中文的 Cookie(解决乱码),并读取验证;
- 实现完整的 "登录 - 保持登录状态 - 退出登录" 流程,验证 Session 的作用;
- 修改 Tomcat 的 Session 默认超时时间为 10 分钟,测试超时后 Session 是否失效。
总结
- 会话管理的核心是 Cookie(客户端存储)和 Session(服务器存储),HTTP 无状态特性通过两者配合实现登录状态保持;
- Cookie 是键值对文本,可设置过期时间,不要存储敏感信息;Session 是服务器对象,通过 JSESSIONID Cookie 关联客户端,安全性更高;
- 实战中,登录时将用户信息存入 Session,请求时读取 Session 验证登录状态,退出时销毁 Session,Cookie 需注意中文乱码和跨域问题。
下一篇【Day35】预告:JSP 核心详解(语法、内置对象、EL 表达式、实战案例),关注专栏持续解锁 Java Web 核心知识点~若本文对你有帮助,欢迎点赞 + 收藏 + 关注,你的支持是我更新的最大动力💖!