Session概览
上文提到了,为了在同一个会话中共享数据(比如用户的登录状态),我们需要使用会话跟踪技术
,Cookie
是客户端
的会话跟踪技术,是存储在本地浏览器中的。而本文介绍另外一种会话跟踪技术Session
,是基于Cookie
实现的技术,是存储在服务端的服务端的会话跟踪技术。
使用Session
获取Session
如果需要基于Session
进行会话跟踪,那么需要在浏览器第一次请求服务器时,在服务端创建一个会话对象Session
,而每一个Session
会话对象,都有一个独一无二的ID
,如图所示:Session括号中的1就表示该Session
的id,称为Session的id:
响应Cookie(JSession)
在服务端成功创建一个Session
之后,在给浏览器响应数据的时候,会通过Cookie将 Session的ID
响应给浏览器。其原理也是通过响应头:Set-Cookie
完成的。上文提到,Set-Cookie响应头
是用来响应Cookie
的,也可以用于响应Session
,这是因为Cookie的名字是固定的,通过JSESSIONID
代表Session
的ID,当浏览器看到响应头中的Cookie
名是JSESSIONID
时,就能自动将其识别为Session
并将这个Cookie
存储在本地浏览器,其原理如图所示:
查找Session
将Cookie
存储在本地浏览器之后,后续的每一次请求,都会将Cookie
中的数据获取出来,通过请求头Cookie
将其携带到服务端,服务端成功获取到JSESSIONID
这个cookie
的值,也就是Session
的独一无二的id值之后,就会从 服务端
中的众多Session
中进行比对,寻找到当前请求对应的Session
,这样我们就可以通过Session
会话对象在同一次会话中的多次请求之间共享数据了,这就是基于Session
进行会话跟踪的流程。
从中不难看出:在大部分情况下Session
的底层是基于Cookie
实现的,二者的使用逻辑、工作原理几乎是相同的。但是Cookie
是存放在本地浏览器的;而Session
是存放在服务器端的。
Session测试代码
在服务端创建Session
响应前端
/**
* 创建Session
* @param session 在服务端创建Session对象
* @return Result<Void>
*/
@GetMapping("/s1")
public Result<Void> setSession(HttpSession session) {
log.info("set-HttpSession: {}", session.hashCode());
// 在session中存储数据
session.setAttribute("login_user", "tom");
return Result.success();
}
我们可以直接操作HttpSession
对象封装响应给客户端
的Session
数据,通过其自带的setAttribute
方法可以便捷封装数据,此时访问/s1
查看:
可以看见,服务端成功响应一个名为JSESSION
的Cookie
,以后的每一次请求,都会携带这个Cookie
,服务端会根据JSESSION
的ID
,去寻找对应的Session
。
在服务端查找对应Session
/**
* 获取Session中数据
* @param request 请求数据封装的对象
* @return Result<Void>
*/
@GetMapping("/s2")
public Result<Object> getSession(HttpServletRequest request) {
HttpSession session = request.getSession();
log.info("get-HttpSession: {}", session.hashCode());
Object loginUser = session.getAttribute("login_user");
log.info("login_user: {}", loginUser);
return Result.success(loginUser);
}
服务端中可以直接操作HttpServletRequest
对象,获取这次请求中所携带的Session
,并使用getAttribute
方法便捷的获取Session
中的数据,服务端查找对应的Session
是根据Session的唯一标识ID
查找到的。此时访问/s2
查看:
对比响应
和请求
中的两个Cookie
的JSESSIONID
可以发现,是使用的同一个Session
,查看控制台日志 发现,服务端成功查找到对应的Session
并成功获取到对应的数据:
这说明通过Session
进行同一次会话中的多次请求共享数据是理论可行的,但真的可行吗?
Session实际不可行
不适应集群环境
现在的大部分项目部署,为了避免单点故障
,都不会只部署在一台服务器上,而是通过集群
的形式进行部署,一个项目会部署在多台服务器上,每一台部署的内容是一样的。通过负载均衡
服务器对用户的请求进行调度,将请求按照服务器的负载,尽量均匀的分配到每一台服务器上:
假如说通过Session
技术进行会话跟踪,那么就有可能出现这样的情况:假如第一次用户登录请求,被负载均衡服务器
分配到了服务器1
,用户完成了登录,在服务器1存储了一个Session
,并将其响应给客户端,以便于每一次请求都携带Cookie
;用户登录之后开始发送其他请求,此时请求被负载均衡服务器
分配到了服务器2
,但Session
是在服务器1的,服务器2无法识别请求头中的Cookie
,所以说判断用户未登录,然后用户又必须登录一次。假如服务器集群十分大,这样的情况就更是频繁。
底层基于Cookie
实现
同时,由于在大部分情况下Session
的底层是基于Cookie
实现的,所以说Cookie
的局限,Session
都是有的。 所以说在实际开发中,Session
使用十分局限。
总结
在大部分情况下,Session
的底层是基于Cookie
实现的,是在存储在服务端的会话跟踪技术
,但由于其不适应服务器集群
、有Cookie的缺点
等局限性,所以使用得并不多。总而言之,不论是Cookie
还是Session
,在实际开发中的使用都比较少,现在大多是通过令牌技术
来实现会话跟踪的,且听下回分解。