HTTP协议自身是属于“无状态”协议
无状态是指:默认情况下,HTTP协议的客户端和服务器之间的这次通信,和下次通信之间没有直接的关系
但在实际开发中,我们很多时候是需要知道请求之间的关联关系的
上述图中的令牌,通常就存储在Cookie字段中,此时在服务器这边就要记录“令牌”信息,以及令牌对应的用户信息,这就是Session机制所做的工作
一、理解Session和Cookie
先来了解一下什么是会话
会话是一个客户与服务器之间不中断的请求响应,对客户的每个请求,服务器能够识别出请求来自于同一个客户,当一个未知的客户向Web应用程序发送第一个请求时就开始了一个会话;当客户结束会话或服务器在一定时限内没有接收到客户的任何请求时,会话就结束了
在服务器并发处理海量请求时(如电商大促秒杀场景),Session(会话对象)是服务端创建的特殊数据结构,用于识别每个请求所属的用户身份和存储并维护会话与用户数据的映射关系(如购物车数据、登录状态)。
Session的本质就是一个"哈希表",存储了一些键值对结构,Key就是SessionID,Value就是用户信息(用户信息可以根据需求灵活设计)
SessionId 在服务器这边是唯一的,前面提到的“令牌”就可以看作为 SessionId,只不过它还会携带一些其他的信息,比如时间,签名等
(1)用户登录的时候,服务器会在Session中新增一个记录,通过HTTP响应中的Set-Cookie字段返回给客户端
(2)客户端后续再次给该服务器发送请求时,会在HTTP请求中的Cookie字段中携带SessionId
(3)服务器收到请求之后,根据SessionId在Session中查找并获取对应的用户信息,再进行后续操作,若找不到就会重新新增一个记录,返回SessionId(回到起初阶段)
Cookie 默认存储在用户的浏览器中,Session 由服务器管理(内存/数据库)
Cookie和Session的区别:
Cookie是客户端保存用户信息的一种机制;Session是服务器保存用户信息的一种机制
Cookie和Session之间主要是通过SessionId关联起来的
二、Cookie
2.1、定义
- 客户端(浏览器)存储的小型文本数据(键值对形式),用于记录用户状态或标识
2.2、获取Cookie
@RestController
@RequestMapping("/Session")
public class GetSessionController {
@RequestMapping("/A1")
public String A1(HttpServletRequest request, HttpServletResponse response){
Cookie[] cookies=request.getCookies();
StringBuilder stringBuilder=new StringBuilder();
if(cookies!=null){
for(Cookie ck:cookies){
stringBuilder.append(ck.getName()+"="+ck.getValue());
}
}
return stringBuilder.toString();
}
}
HttpServletRequest,HttpServletResponse是Servlet提供的两个类,是Spring MVC方法的内置对象
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中所有的信息都封转在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息
HttpServletResponse对象代表服务器的响应,HTTP响应的信息都在这个对象中,通过该对象的方法,可以获得服务器响应的所有内容
访问后得到了设置的Cookie:
2.3、使用注解获取Cookie
@RequestMapping("/A2")
public String A2(@CookieValue("name") String name){
return "name为:"+name;
}
三、Session
3.1、定义
- 服务器创建的会话状态存储结构,本质是 内存/数据库中的键值表
3.2、存储Session
Session是服务器端的机制,我们需要先存储,才能获取,Session是基于HttpServletRequest来存储和获取的
@RequestMapping("/A3")
public String A3(HttpServletRequest request){
HttpSession session=request.getSession();
if (session!=null){
session.setAttribute("userName","Aokey");
}
return "Session设置成功";
}
运行后可以看到,HTTP响应后通过Set-Cookie告知客户端,把SessionID 存储在Cookies中
3.3、获取Session
(1)HttpSession.getSession(boolean create);参数如果为true,那么当不存在会话时新建会话;如果为false,不存在会话时返回null;
(2)HttpSession.getSession();参数默认为true
@RequestMapping("/A4")
public String A4(HttpServletRequest request){
HttpSession session=request.getSession(false);
if(session==null){
return "用户未登录";
}else {
String useName=(String) session.getAttribute("userName");
Integer age=(Integer) session.getAttribute("age");
return "姓名:"+ useName+" 年龄:"+age;
}
}
先后访问:http://127.0.0.1:8080/Session/A3 和 http://127.0.0.1:8080/Session/A4
Fiddler抓包后发现:
3.4、通过注解获取Session
@RequestMapping("/A5")
public String A5(@SessionAttribute("userName" ) String userName,@SessionAttribute("age") Integer age){
return "姓名:"+ userName +" 年龄:"+age;
}
通过Spring MVC内置对象HttpSession来获取
@RequestMapping("/A6")
public String A6(HttpSession session){
String userName=(String) session.getAttribute("userName");
Integer age=(Integer) session.getAttribute("age");
return "姓名:"+ userName +" 年龄:"+age;
}
四、Header
4.1、获取Header
获取Header也是通过HttpServletRequest对象获取
@RequestMapping("/A7")
public String A7(HttpServletRequest request){
String string=request.getHeader("Cookie");
return "获取到Cookie为:"+string;
}
运行结果:http://127.0.0.1:8080/Session/A7
4.2、使用注解获取Header
@RequestMapping("/A8")
public String A8(@RequestHeader("Cookie") String string){
return "获取到Cookie为:"+string;
}