Servlet Session 跟踪
一、什么是 Session 跟踪?
Session 跟踪是 Web 应用中用于维护用户状态的一种服务器端机制。在 HTTP 协议无状态的特性下,服务器需要一种方式来识别同一用户的多次请求。Session 允许服务器为每个用户创建一个会话对象,用于存储用户特定的数据(如登录信息、购物车等)。
- Session 的工作原理:
- 当用户首次访问服务器时,服务器创建一个 Session 对象,并生成一个唯一的 Session ID。
- Session ID 通常通过 Cookie 发送给客户端(Cookie 名为 JSESSIONID)。
- 后续请求中,客户端会携带这个 Session ID,服务器据此找到对应的 Session 对象。
- 如果浏览器禁用 Cookie,Session ID 可以通过 URL 重写(URL Rewriting)来传递。
- 与 Cookie 的区别:
- Cookie:数据存储在客户端,适合少量非敏感数据。
- Session:数据存储在服务器端,更安全,适合存储敏感或大量数据。
Session 在 Servlet 中通过 javax.servlet.http.HttpSession
接口实现。
二、Servlet 中 Session 的操作
在 Servlet 中,可以通过 HttpServletRequest
获取或创建 Session。以下是常见操作的步骤和代码示例。
1. 创建和获取 Session
使用 request.getSession()
方法获取 Session。如果不存在,会自动创建一个新 Session。
代码示例:
import javax.servlet.http.*;
import java.io.IOException;
public class CreateSessionServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// 获取或创建 Session
HttpSession session = request.getSession();
// 获取 Session ID
String sessionId = session.getId();
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("Session 已创建,ID: " + sessionId);
}
}
说明:
request.getSession()
:如果 Session 已存在,返回现有 Session;否则创建一个新 Session。request.getSession(false)
:如果不存在,返回 null,不会创建新 Session。- Session ID 通过 Cookie(JSESSIONID)自动发送给客户端。
2. 设置 Session 属性
Session 可以存储键值对形式的属性,支持任意 Java 对象。
代码示例:
import javax.servlet.http.*;
import java.io.IOException;
public class SetSessionAttributeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
HttpSession session = request.getSession();
// 设置属性
session.setAttribute("username", "张三");
session.setAttribute("age", 25); // 支持任意对象
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("Session 属性已设置!");
}
}
说明:
setAttribute(String name, Object value)
:设置名为name
的属性,值为value
。- 属性存储在服务器内存中,多个请求可共享。
3. 获取 Session 属性
从 Session 中读取属性值。
代码示例:
import javax.servlet.http.*;
import java.io.IOException;
public class GetSessionAttributeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
HttpSession session = request.getSession(false); // 不创建新 Session
if (session != null) {
String username = (String) session.getAttribute("username");
Integer age = (Integer) session.getAttribute("age");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("用户名: " + username + ", 年龄: " + age);
} else {
response.getWriter().write("Session 不存在!");
}
}
}
说明:
getAttribute(String name)
:返回属性值,需要类型转换。- 如果属性不存在,返回 null。
4. 删除 Session 属性或使 Session 失效
- 删除单个属性:
removeAttribute(String name)
。 - 使整个 Session 失效:
invalidate()
,通常用于用户注销。
代码示例:
import javax.servlet.http.*;
import java.io.IOException;
public class InvalidateSessionServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
HttpSession session = request.getSession(false);
if (session != null) {
// 删除单个属性
session.removeAttribute("username");
// 使 Session 失效
session.invalidate();
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("Session 已失效!");
} else {
response.getWriter().write("Session 不存在!");
}
}
}
说明:
invalidate()
:销毁 Session,客户端的 JSESSIONID Cookie 也会被删除。- 失效后,再次调用
getSession()
会创建一个新 Session。
5. Session 超时设置
Session 有默认超时时间(通常 30 分钟),可以通过配置修改。
- 在代码中设置:
session.setMaxInactiveInterval(int seconds)
。 - 在 web.xml 中全局设置:
<session-config>
<session-timeout>30</session-timeout> <!-- 单位:分钟 -->
</session-config>
代码示例:
HttpSession session = request.getSession();
session.setMaxInactiveInterval(60 * 60); // 设置超时为 1 小时(单位:秒)
三、处理中文 Session
Session 属性值支持中文,但需确保请求和响应的编码一致,以避免乱码。
1. 设置中文属性
确保请求参数的编码正确(通常使用 UTF-8)。
代码示例:
import javax.servlet.http.*;
import java.io.IOException;
public class SetChineseSessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// 设置请求编码
request.setCharacterEncoding("UTF-8");
HttpSession session = request.getSession();
String chineseName = request.getParameter("name"); // 假设从表单获取中文
session.setAttribute("username", chineseName);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("中文 Session 属性已设置!");
}
}
说明:
request.setCharacterEncoding("UTF-8")
:处理 POST 请求中的中文参数。- 对于 GET 请求,需在服务器配置中确保 URI 编码为 UTF-8。
2. 获取中文属性
响应时设置 UTF-8 编码。
代码示例:
// 同上获取示例,response.setContentType("text/html;charset=UTF-8");
String username = (String) session.getAttribute("username");
response.getWriter().write("用户名: " + username);
说明:
- Session 内部存储对象时不涉及编码问题,但输入/输出时需注意。
四、Session 跟踪的其他机制
如果浏览器禁用 Cookie,Session ID 可以通过 URL 重写传递。
- 使用
response.encodeURL(String url)
或response.encodeRedirectURL(String url)
来重写 URL,自动附加 Session ID(如;jsessionid=xxx
)。
代码示例:
String url = response.encodeURL("/nextServlet"); // 重写 URL
response.getWriter().write("<a href='" + url + "'>下一步</a>");
说明:
- 这确保了在无 Cookie 时 Session 仍可跟踪,但会暴露 Session ID,安全性较低。
五、注意事项
- 安全性:
- Session 数据存储在服务器,较 Cookie 安全,但需防范 Session 劫持(使用 HTTPS)。
- 避免存储敏感数据,如密码;使用散列或加密。
- 性能:
- Session 占用服务器内存,大量用户时可能导致内存溢出。使用分布式 Session(如 Redis)来扩展。
- 设置合理的超时时间,避免无用 Session 积累。
- 中文编码问题:
- 始终设置
request.setCharacterEncoding("UTF-8")
和response.setContentType("text/html;charset=UTF-8")
。 - 在 web.xml 或服务器配置中指定默认编码。
- Session 生命周期:
- 创建:首次
getSession()
。 - 失效:超时、
invalidate()
、服务器重启或浏览器关闭(对于依赖 Cookie 的 Session)。 - 获取创建时间:
session.getCreationTime()
;最后访问时间:session.getLastAccessedTime()
。
- 浏览器兼容:
- 如果禁用 Cookie,需使用 URL 重写作为备用。
- 不同浏览器对 Session ID 的处理可能略有差异。
六、常见问题与解决方案
- 问题:Session 中文乱码。
- 解决:设置请求和响应的编码为 UTF-8。
- 问题:Session 丢失。
- 解决:检查 Cookie 是否启用;使用 URL 重写;确保 Session ID 未过期。
- 问题:Session 不失效。
- 解决:调用
invalidate()
或检查超时设置。
七、总结
Servlet 中的 Session 跟踪是一种强大的服务器端状态管理机制,通过 HttpSession 接口实现数据的存储和检索。它比 Cookie 更安全,适合处理用户会话。处理中文时,重点在于编码一致性。同时,结合 URL 重写可以应对 Cookie 禁用场景。在实际开发中,合理管理 Session 的生命周期和安全性,能显著提升 Web 应用的体验。
如果需要更多示例或特定场景的讲解,请继续提问!