【JavaWeb】Cookie & Session
前言
本文为JavaWeb基础Cookie 和 Session相关知识详细介绍,**Java全栈学习路线可参考:**[【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引](https://blog.csdn.net/qq_42146402/article/details/127133435),内含最全Java全栈学习技术清单
一、关于 Http 无状态的理解
什么 Http 无状态:
- 服务器不会保留客户端交易的任何状态和数据,一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接,这就意味着服务器无法从连接上跟踪会话。也就是指用户每次发起的请求之间是没有相关性的,每次的请求结束就结束了,不会在做任何数据的存储。
Http 请求的无状态带来的问题和影响:
- 比如用户登录以后切换到别的界面进行操作,服务器端根本无法判别是哪个用户登录的,每次进行页面跳转的时候都要重新登录。
如何解决 Http 请求的无状态的问题:
- 1:Session(服务器端)
- 2:Cookie(客户端)
- 3:Html5 中:window.localStorage(客户端)
- 4:Jwt + Token 机制(客户端)
所以 Session、Cookie 并不是 Http 协议自身的技术点,而是 Java 语言为了弥补 Http 无状态的问题而产生成的一种技术机制。
二、解决 Http 无状态的问题
如果要解决 Http 无状态的问题,无外乎就是在服务器端或客户端存储数据信息。
服务器端存储数据信息的方式:
- 1:数组:Object[] obj = new Object[10000],数组长度固定,无法扩容,开小不够,开大浪费内存空间,不合适。
- 2:集合:ArrayList,查找速度很慢,时间复杂度为 O(n),不合适。
- 3:Map:数组 + 链接,时间复杂度为 Q(1),最佳选择方案。
客户端存储数据信息的方式:
- Cookie 或 Storage。
完整交互:
- 服务器端把用户登录的信息存储到浏览器的 Cookie 或 Storage 中并分配给浏览器一个唯一 key,然后以 Cookie的形式发送到浏览器,后续用户通过浏览器请求访问其他页面或发起请求时都携带这个 Cookie,就可以得知用户已经登录,而这个 key 就是Session。
存在的问题:
- 1:key 是暴露出来的,不安全。
- 2:如何保证用户登录以及失效的问题。
解决方案:
- 1:把 key 从参数移除,放到请求头中进行传输。
- 2:心跳检测(守护线程),一直在监听 map 的 key 创建的时机,和用户最后一次访问的时间比较,如果这个时间超过 30
分钟,就直接在服务器上自动删除 key。一是考虑到服务器的内存消耗,二是考虑到保护用户信息的安全性。
三、Session的介绍与使用
1.Session简介
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。
- Session数据存储在服务器端,存储的类型是没有限制的,包括且不限于string,integer,list,map等
- session存储在服务器上,对客户端是透明的,不存在敏感信息泄漏的风险
- Session用于存储一次会话的多次请求的数据,存在服务器端
- Session不支持跨域名访问
2.Session的使用
(1)服务端编写一个首页的 Servlet 类来存放 Session。
@WebServlet("/page/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// request.setAttribute("username","yykk");
HttpSession session = request.getSession();
session.setAttribute("username","yykksession");
request.getRequestDispatcher("/index.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
(2)客户端浏览器会把这个 sessionid 写入到浏览器的 Cookie 中进行存放,方便后续的每个请求都携带这个 sessionid 进行访问。
(3)服务端编写一个用户中心的 Servlet 类,用户中心发起请求时会通过 Cookie 的 Domain 和 Path 确认,如果这个请求是在同一个 Cookie 的域和上下文中,就会在请求头中携带 sessionid 请求服务器,如果这个 sessionid 和服务器的 sessionid 相同就会直接获取 Session 进行后续操作。
@WebServlet("/user/index")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
(4)Session 会话时长默认是 30 分钟,可以通过配置修改。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
四、Cookie的介绍与使用
1.Cookie简介
Cookie:有时也用其复数形式Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
- Cookie数据存储在客户端,存储的类型只能是String,并且是又大小限制的,一般为4KB。
- Cookie的持久化存储,使用setMaxAge()来设置存储的时间,如果不设置,默认关闭浏览器即是删除。
- Cookie对客户端是可见的,别有C用心的人可以分析存放在本地的cookie并进行cookie欺骗,所以一般都不用Cookie来存储敏感信息,一般是用来作服务器对客户端的用户识别。
- Cookie支持跨域名访问。
2.Cookie的使用
实际上,Servlet 提供的 HttpSession 本质上就是通过 Cookie 中的 JSESSIONID 去跟踪用户会话。除了这个名称外,其他名称的 Cookie 都可以任意使用。
(1)自定义 Cookie 记录用户选择的语言。
@WebServlet(urlPatterns = "/pref")
public class LanguageServlet extends HttpServlet {
private static final Set<String> LANGUAGES = Set.of("en", "zh");
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String lang = req.getParameter("lang");
if (LANGUAGES.contains(lang)) {
// 指定名称和值
Cookie cookie = new Cookie("lang", lang);
// 在请求以/开头的路径时附加此Cookie
cookie.setPath("/");
// 如果是https网页
// cookie.setSecure(true);
// 添加到响应
resp.addCookie(cookie);
}
resp.sendRedirect("/");
}
}
(2)读取 Cookie。
private String parseLanguageFromCookie(HttpServletRequest req) {
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("lang")) {
return cookie.getValue();
}
}
}
return "en";
}
五、Session和Cookie的原理
- Session 原理: 其实是一种服务端的数据存储技术,存储在 StandardSession 类的 ConcurrentHashMap 集合中。为了维护每个请求的数据关系,会生成一个 jsessionid 并通过 Cookie写入客户端。后面在浏览器的每个请求的过程中都会比较请求的域和 Cookie 的域是否相同,如果相同,浏览器会把所有 Cookie 中存放的key 一起打包,放入到请求头中,发送给服务器。然后服务器会根据 request 对象解析请求头中 Cookie,如果该数据信息 jsessionid 和请求头中 Cookie 里 jsessionid 名字且值都相同,就直接返回一个 Session对象,如果找不到,说明会话已经失效。
- Cookie 原理: 其实是一种客户端的数据存储技术,它会把数据写入到浏览器中,不会占用服务器的内存,所以在很多时候,如果仅仅只是临时的保存一些数据信息,但是又不想存储数据库表,那么可以考虑使用Cookie 技术。其实 JavaScript 也可以操作 Cookie。比如用户登录记录登录状态,就可以考虑使用Cookie。比如视频网站播放的时候,记录当前播放进度或者音量等等,也可以考虑使用 Cookie。
- Session与Cookie的区别: Session存储数据在服务器端,Cookie在客户端;Session没有数据类型大小限制,Cookie有数据类型限制,仅限String类型,<=4KB;Session数据安全,Cookie相对于不安全。
六、Session 和 Cookie存在的问题
- Cookie 存在的问题:安全问题和大小问题。现在的比较常见的解决方案:localStorage /sessionStorage。Chrome 浏览器中 localStorage 最大 5120kb,即 5M。
- Session 存在的问题:占用服务器的内存,当服务器空间不够时只能做负载均衡。
后记
Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~