会话管理
什么是会话管理
会话管理(Session Management) 是 Web 开发中的一个重要概念,主要用于跟踪用户在网站上的活动状态。由于 HTTP 协议是无状态的(即每次请求都是独立的,服务器不会记住之前的请求),因此需要通过会话管理技术来维护用户的状态信息。
为什么需要会话管理
因为 HTTP 是无状态协议。
无状态就是不保存状态,即无状态协议(stateless),HTTP 协议自身不对请求和响应之间的通信状态进行保存,也就是说,在 HTTP 协议这个级别,协议对于发送过的请求或者响应都不做持久化处理。简单理解:浏览器发送请求,服务器接收并响应,但是服务器不记录请求是否来自哪个浏览器,服务器没记录浏览器的特征,就是客户端的状态。
举例:张三去一家饭馆点了几道菜,觉得味道不错,第二天又去了,对老板说,还点上次的那几道菜。
无状态:老板没有记录张三是否来过,更没有记录上次他点了那些菜,张三只能重新再点一遍。有状态:老板把每次来吃饭的用户都做好记录,查阅一下之前的记录,查到了张三之前的菜单,直接下单。
会话管理的作用
跟踪用户状态:识别用户并保持其状态。维护用户数据:存储和检索用户相关的数据。实现身份验证和授权:管理用户登录和权限控制。提高用户体验:提供个性化的服务和功能。实现跨页面数据共享:在多个页面间传递数据。增强安全性:防止恶意攻击和滥用。支持分布式系统:在集群环境中共享用户状态。
会话管理实现的方式
在 JavaWeb 中,会话管理主要通过以下两种方式实现:Cookie 和 Session。
Cookie
Cookie 是服务器发送到客户端(浏览器)的一小段数据,浏览器会将其保存,并在后续的请求中自动发送回服务器。Cookie 通常用于存储一些简单的用户信息,比如用户偏好、登录状态等。
Cookie 的工作流程
服务端创建 Cookie,将 Cookie 放入响应对象中,Tomcat 容器将 Cookie 转化为 set-cookie 响应头,响应给客户端。客户端在收到 Cookie 的响应头时,在下次请求该服务的资源时,会以 Cookie 请求头的形式携带之前收到的 Cookie。Cookie 是一种键值对格式的数据,从 tomcat8.5 开始可以保存中文,但是不推荐。由于 Cookie 是存储于客户端的数据,比较容易暴露,一般不存储一些敏感或者影响安全的数据。
Cookie 的特点
存储在客户端(浏览器)。大小有限制(通常每个 Cookie 不超过 4KB)。可以设置过期时间,分为会话 Cookie(关闭浏览器后失效)和持久 Cookie(在指定时间内有效)。每次请求都会自动发送到服务器,可能会增加网络开销。
Cookie 的时效性
默认情况下 Cookie 的有效期是一次会话范围内,我们可以通过 Cookie 的 setMaxAge() 方法让 Cookie 持久化保存到浏览器上。
会话级 Cookie(Session Cookie)
服务器端并没有明确指定 Cookie 的存在时间。在浏览器端,Cookie 数据存在于内存中。只要浏览器还开着,Cookie 数据就一直都在。浏览器关闭,内存中的 Cookie 数据就会被释放。
持久化 Cookie(Persistent Cookie)
服务器端明确设置了 Cookie 的存在时间。在浏览器端,Cookie 数据会被保存到硬盘上。Cookie 在硬盘上存在的时间根据服务器端限定的时间来管控,不受浏览器关闭的影响。持久化 Cookie 到达了预设的时间会被释放。
代码示例
// 创建 Cookie
Cookie cookie = new Cookie("username", "JohnDoe");
cookie.setMaxAge(60 * 60 * 24); // 设置有效期为 1 天
response.addCookie(cookie); // 添加到响应中
// 读取 Cookie
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
if ("username".equals(c.getName())) {
String username = c.getValue();
System.out.println("Username: " + username);
}
}
}
如果请求中没有 Cookie,request.getCookies()会返回 null。
Session
Session 是服务器端的一种会话管理技术。服务器会为每个用户创建一个唯一的 Session 对象,并分配一个 Session ID。这个 Session ID 通常通过 Cookie 发送到客户端,后续请求中客户端会携带这个 Session ID,服务器通过它来识别用户。
Session 的工作流程
服务端在为客户端创建 Session 时,会同时将 Session ID,即 JSESSIONID 以 Cookie 的形式放入响应对象。后端创建完 Session 后,客户端会收到一个特殊的 Cookie,叫做 JSESSIONID。客户端下一次请求时携带 JSESSIONID,后端收到后,根据 JSESSIONID 找到对应的 Session 对象。通过该机制,服务端通过 Session 就可以存储一些专门针对某个客户端的信息了。Session 是域对象。
Session 的特点
存储在服务器端,安全性较高。可以存储较大的数据(如用户信息、购物车内容等)。依赖于 Cookie 或 URL 重写来传递 Session ID。默认情况下,Session 在用户关闭浏览器后失效(也可以通过配置设置过期时间)。
代码示例
// 获取 Session
HttpSession session = request.getSession();
// 存储数据到 Session
session.setAttribute("username", "JohnDoe");
// 从 Session 中获取数据
String username = (String) session.getAttribute("username");
System.out.println("Username: " + username);
// 使 Session 失效(用户注销时调用)
session.invalidate();
getSession() 方法的处理逻辑
Session 的时效性
是指 Session 在服务器端的有效时间。Session 是服务器用来跟踪用户状态的一种机制,它的生命周期由服务器控制。Session 的时效性直接影响用户的状态管理,例如用户登录状态、购物车内容等。
Session 的生命周期
Session 的生命周期从创建开始,到失效结束。具体分为以下几个阶段:
创建:当用户第一次访问服务器时,服务器会为该用户创建一个唯一的 Session,并分配一个 Session ID。使用:在用户与服务器的交互过程中,Session 可以存储和读取用户相关的数据。失效:Session 会在以下情况下失效:
用户长时间未活动(超过指定的超时时间)。服务器主动销毁 Session(如调用 session.invalidate())。用户关闭浏览器(仅对未设置持久化的情况有效)。
Session 的默认时效性
在大多数 Web 服务器(如 Tomcat)中,Session 的默认超时时间为 30 分钟。这意味着如果用户在 30 分钟内没有与服务器进行任何交互,Session 将自动失效。
查看和修改默认超时时间
在 web.xml 文件中,可以通过
Session 时效性的控制方法
在 Java 中,可以通过以下方式控制 Session 的时效性:
(1) 设置全局超时时间
在 web.xml 中配置
(2) 在代码中动态设置超时时间
通过 HttpSession 的 setMaxInactiveInterval() 方法设置 Session 的超时时间(单位为秒):
HttpSession session = request.getSession();
session.setMaxInactiveInterval(60 * 60); // 设置超时时间为 1 小时
(3) 立即销毁 Session
通过 invalidate() 方法可以立即销毁 Session:
HttpSession session = request.getSession();
session.invalidate(); // 销毁 Session
(4) 设置 Session 永久有效
通过将超时时间设置为一个非常大的值,可以让 Session 几乎永久有效:
HttpSession session = request.getSession();
session.setMaxInactiveInterval(Integer.MAX_VALUE); // 设置 Session 永久有效
Session 失效的触发条件
Session 会在以下情况下失效:
超时:用户在规定时间内未与服务器交互。
主动销毁:调用 session.invalidate() 方法。
服务器重启或崩溃:Session 数据丢失(除非使用持久化存储,如 Redis)。
浏览器关闭:如果 Session ID 是通过 Cookie 传递的,浏览器关闭后 Cookie 失效,Session 无法被访问(但服务器端的 Session 仍然存在,直到超时)。
Session 时效性的注意事项
性能影响:过多的 Session 会占用服务器内存,因此需要合理设置超时时间。分布式环境:在分布式系统中,Session 需要共享(如使用 Redis 存储 Session),以确保不同服务器可以访问同一 Session。安全性:Session 失效后,用户的登录状态和其他敏感信息会被清除,因此合理设置超时时间可以增强安全性。
Session 时效性的应用场景
用户登录状态管理:
用户登录后,Session 存储用户信息,超时后自动注销。
购物车功能:
用户将商品加入购物车后,Session 存储购物车数据,超时后清空购物车。
临时数据存储:
在多步骤操作(如注册流程)中,每一步的数据可以存储在 Session 中,超时后清除。
Session 时效性与 Cookie 的关系
Session 的时效性通常依赖于 Cookie 来传递 Session ID。如果浏览器关闭,会话 Cookie 会失效,但服务器端的 Session 仍然存在,直到超时。如果需要持久化 Session,可以将 Session ID 存储在持久 Cookie 中。
Cookie 和 Session 的区别
特性CookieSession存储位置客户端(浏览器)服务器端安全性较低(容易被篡改或窃取)较高(数据存储在服务器)存储大小较小(通常不超过 4KB)较大(取决于服务器配置)生命周期可以设置过期时间默认随浏览器关闭失效,可配置性能影响每次请求都会携带,增加网络开销仅在服务器端存储,性能较好会话管理的应用场景
用户登录状态管理
用户登录后,服务器生成一个 Session 并存储用户信息,同时将 Session ID 通过 Cookie 发送给客户端。后续请求中,客户端携带 Session ID,服务器通过它识别用户并验证登录状态。
购物车功能
用户将商品加入购物车后,可以将购物车信息存储在 Session 中,确保用户在不同页面间浏览时购物车内容保持一致。
用户偏好设置
使用 Cookie 存储用户的主题偏好、语言设置等,方便下次访问时自动加载。
会话管理的注意事项
安全性
Cookie 容易被窃取或篡改,因此敏感信息(如密码)不应存储在 Cookie 中。对于 Session,应确保 Session ID 的安全性,防止 Session 劫持。
性能
如果 Session 中存储了大量数据,可能会影响服务器性能,因此需要合理设计 Session 的使用。
分布式环境
在分布式系统中,Session 需要共享(如使用 Redis 存储 Session),以确保不同服务器可以访问同一 Session。
三大域对象
什么是域对象
域对象(Scope Object)是一种可以在特定范围内存储和共享数据的对象。它们提供了一种机制,允许在不同的 JavaWeb 组件(如 Servlet、JSP 页面等)之间传递和共享数据,根据数据的共享范围不同,大体可以分为三类:应用域(ServletContext)、会话域(HttpSession)和请求域(HttpSessionRequest)。
ServletContext(应用域)
ServletContext 是 JavaWeb 中作用范围最大的域对象,它代表整个 Web 应用。一个 Web 应用只有一个 ServletContext 对象,所有的 Servlet 和 JSP 页面都可以共享其中的数据。
特点
生命周期:
创建:Web 应用启动时创建。销毁:Web 应用关闭或服务器停止时销毁。
作用范围:整个 Web 应用(所有用户共享)。线程安全性:非线程安全,需要手动同步。
使用场景
存储全局配置信息(如数据库连接信息)。共享应用级别的数据(如网站访问次数)。
HttpSession(会话域)
HttpSession 是用于跟踪用户会话的域对象。每个用户都有一个独立的 HttpSession 对象,用于存储用户相关的数据。
特点
生命周期:
创建:用户第一次访问服务器时创建。销毁:用户长时间未活动(超时)、调用 invalidate() 方法、服务器重启时销毁。
作用范围:一次用户会话(同一用户的多次请求共享)。线程安全性:非线程安全,需要手动同步。
使用场景
存储用户登录状态。存储购物车信息。存储用户偏好设置。
HttpServletRequest(请求域)
HttpServletRequest 是用于在一次请求中共享数据的域对象。它的生命周期最短,仅在一次请求范围内有效。
特点
生命周期:
创建:每次请求时创建。销毁:请求结束时销毁。
作用范围:一次请求(请求转发时共享)。线程安全性:线程安全(每个请求独立)。
使用场景
在请求转发(Forward)时传递数据。存储临时数据(如表单数据)。
所有域合在一起
域对象常用方法
API功能void setAttribute(String name,String value)向域对象中添加/修改数据Object getAttribute(String name);从域对象中获取数据removeAttribute(String name);移除域对象中的数据代码示例
ServletA 向三大域中放入数据:
@WebServlet("/servletA")
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 向请求域中放入数据
req.setAttribute("request","request-message");
//req.getRequestDispatcher("servletB").forward(req,resp);
// 向会话域中放入数据
HttpSession session = req.getSession();
session.setAttribute("session","session-message");
// 向应用域中放入数据
ServletContext application = getServletContext();
application.setAttribute("application","application-message");
}
}
ServletB 从三大域中取出数据:
@WebServlet("/servletB")
public class ServletB extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从请求域中获取数据
String reqMessage =(String)req.getAttribute("request");
System.out.println(reqMessage);
// 从会话域中获取数据
HttpSession session = req.getSession();
String sessionMessage =(String)session.getAttribute("session");
System.out.println(sessionMessage);
// 从应用域中获取数据
ServletContext application = getServletContext();
String applicationMessage =(String)application.getAttribute("application");
System.out.println(applicationMessage);
}
}
三大域对象的对比
特性ServletContext(应用域)HttpSession(会话域)HttpServletRequest(请求域)生命周期应用启动到关闭用户会话期间一次请求期间作用范围整个 Web 应用(全局共享)一次用户会话(用户共享)一次请求(请求共享)线程安全性非线程安全非线程安全线程安全适用场景全局配置、共享数据用户状态、购物车请求转发、临时数据如何选择合适的域对象
ServletContext:适合存储全局共享的数据,所有用户都可以访问。HttpSession:适合存储用户级别的数据,如登录状态、购物车等。HttpServletRequest:适合存储临时数据,如表单数据或请求转发时的数据。
注意事项
性能:
ServletContext 存储的数据会一直存在,占用内存,因此不要存储过多数据。HttpSession 存储的数据在用户会话期间有效,可能会占用较多内存,尤其是在用户量大的情况下。
线程安全:
ServletContext 和 HttpSession 是非线程安全的,多线程环境下需要手动同步。HttpServletRequest 是线程安全的,每个请求独立。
分布式环境:
在分布式系统中,HttpSession 需要共享(如使用 Redis 存储),以确保不同服务器可以访问同一 Session。
总结
三大域对象是 JavaWeb 开发中非常重要的数据共享机制,合理使用它们可以提高代码的可维护性和性能。以下是它们的核心特点:
ServletContext:全局共享,生命周期最长。HttpSession:用户会话共享,生命周期中等。HttpServletRequest:请求共享,生命周期最短。