目录
一、理解Cookie
HTTP协议自身是属于“无状态”协议。
无状态的含义指的是:默认情况下HTTP协议的客户端和服务器之间的这次通信和下次通信之间没有之间的关系。
但是实际开发中,我们很多时候是需要知道请求之间的关联关系的。
例如登陆网站成功后,第二次访问的时候服务器就能知道该请求是否是已经登陆过了。
上述图中的令牌通常就存储在Cookie字段中。
例子:比如去医院挂号
- 看病之前先挂号,挂号的时候需要提供身份证号,同时得到一张就诊卡,这个就诊卡就相当于患者的令牌。
- 后续去各个科室进行检查,诊断,开药等操作,就不必再出示身份证了,只要凭就诊卡即可识别出当前患者的身份。
- 看完病之后,不想要就诊卡了,就可以注销这个卡,此时患者的身份和就诊卡的关联就销毁了(类似于网站的注销操作)
- 又来看病,可以办一张新的就诊卡,此时就得到了一个新的令牌。
此时在服务器这边就需要记录令牌信息,以及令牌对应的用户信息,这就是Session机制所做的工作。
二、理解Session
我们先来了解什么是会话。
会话是一个客户与服务器之间的不中断的请求响应,对客户的每个请求,服务器能够识别出请求来自同一个客户,当一个未知的客户向Web应用程序发送第一个请求时就开始了一个会话,当客户明确结束会话或服务器在一个时限内没有接受到客户请求时,会话就结束了。
服务器同一时刻收到的请求是很多的,服务器需要清楚的区分每个请求是属于哪个用户,也就是属于哪个会话,就需要在服务器这边记录每个会话以及与用户的信息的对应关系。
Session是服务器为了保存用户信息而创建的一个特殊的对象。
SessionId是由服务器生成的一个“唯一性字符串”,从Session机制的角度来看,这个唯一性字符串称为“Sessionid”。
上图很好的解释了服务器同一时刻可以接受很多请求,而且能够分清楚收到的请求属于哪个客户发来的,是因为服务器生成了一个SessionId,然后返回给客户端,返回就带有这个SessionId,也就是所说的“令牌”。
Session的本质就是一个哈希表,存储了一些键值对结构,Key就是SessionId,Value就是用户信息。
- 当用户登陆的时候,服务器在Session中新增一个新纪录,并把SessionId返回给客户端。(通过HTTP响应中的Set-Cookie字段返回)。
- 客户端后续再给服务器发送请求的时候,需要再请求中带上SessionId。(通过HTTP请求中的Cookie字段带上)。
- 服务器收到请求之后,根据请求中的SessionId在Session信息中获取对应的信息,再进行后续操作。找不到则重新创建Session,并把SessionId返回。
注意:Session默认是保存在内存中的,如果重启服务器则Session数据就会丢失。
三、Cookie和Session的区别
- Cookie是客户端保存用户信息的一种机制,Session是服务器保存用户信息的一种机制。
- Cookie和Session之间主要是通过SessionId关联起来的,SessionId是Cookie和Session之间桥梁。
- Cookie和Session经常会在一起配合,但是不是必须配合。
四、核心方法
HttpServletRequest类中的相关方法
方法 | 返回值 | 描述 |
getSession() | HttpSession | 在服务器中获取会话,参数如果为true,则当不存在会话时创建会话; 如果参数为false,则当不存在会话时返回null |
getCookies() | Cookie[] | 返回一个数组,包含客户端发送该请求的所有的Cookie对象,会自动 把Cookie中的格式解析成键值对 |
HttpServletResponse类中的相关方法
方法 | 描述 |
void addCookie(Cookie cookie) | 把指定的cookie添加到响应中 |
HttpSession类中的相关方法
一个HttpSession对象里面包含多个键值对,我们可以往HttpSession中存放我们需要的信息。
方法 | 描述 |
Object getAttribute(String name) | 该方法返回在该session会话中具体指定名称的对象,如果没有指定名称的对象,返回null |
void setAttribute(String name, Object value) | 该方法使用指定的名称绑定一个对象到该session会话 |
boolean isNew() | 判断当前是否是新创建出的会话 |
Cookie类中的相关方法
每个Cookie对象就是一个键值对。
方法 | 描述 |
String getName() | 该方法返回cookie的名称。名称在创建后不能改变。(这个值是Set-Cookie字段设置给浏览器的) |
String getValue() | 该方法获取与cookie关联的值 |
void setValue(String newValue) | 该方法设置与cookie关联的值 |
五、获取Cookie
5.1 传统获取Cookie
@RequestMapping("/m10")
public String method10(HttpServletRequest request, HttpServletResponse response) {
//获取所有cookie信息
Cookie[] cookies = request.getCookies();
//打印cookie信息
StringBuilder stringBuilder = new StringBuilder();
if (cookies != null) {
for (Cookie cookie : cookies) {
stringBuilder.append(cookie.getName() + ":" + cookie.getValue());
}
}
return "Cookie信息:" + stringBuilder;
}
Spring MVC是基于Servlet API构建的原始Web框架,也是在Servlet的基础上实现的。
HttpServletRequest,HttpServletResponse是Servlet提供的两个类,是Spring MVC方法的内置对象,需要时直接在方法中添加声明即可。
从这个例子中,可以看出Cookie是可以伪造的,也就是不安全的,所以使用Cookie时,后端需要进行Cookie校验。
5.2 简洁获取Cookie
@RequestMapping("/getCookie")
public String cookie(@CookieValue("bite") String bite) {
return "bite:" + bite;
}
六、Sesion的存储和获取
Session是服务器端的机制,需要我们先存储,才能再获取,Session也是基于HttpServletRequest来存储和获取的。
6.1 Session存储
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request) {
//获取Session对象
//参数如果为true,则当不存在会话时创建会话,参数如果为false,则当不存在会话时返回null,
//getSession()和getSession(true)含义一样,默认值为true
HttpSession session = request.getSession();
if (session != null) {
session.setAttribute("username", "zhangsan");
}
return "session存储成功";
}
6.2 传统Sesion读取
@RequestMapping("/getSession")
public String getSession(HttpServletRequest request) {
//如果session不存在不会创建
HttpSession session = request.getSession(false);
String username = null;
if (session != null && session.getAttribute("username") != null) {
username = (String) session.getAttribute("username");
}
return "username:" + username;
}
通过Fiddler观察Http请求和响应情况:
可以看出,Http响应中,通过Set-Cookie告诉客户端,把SessionId存储在Cookie中,通过浏览器,可以观察到运行结果:
可以看出,HTTP请求时,把SessionId通过Cookie传递给服务器。
6.3 简洁获取Session
@RequestMapping("/getSession2")
public String getSession2(@SessionAttribute(value = "username", required = false) String username) {
return "username: " + username;
}