参考牛客网高级项目教程
1.使用会话管理原因
HTTP无状态特点
-
即 1.HTTP本身是无状态的,即使同一个浏览器与服务端,多个请求直接是不能直接会话的
- 因为,每个请求对于服务器来说,都是陌生的,
- 只在每条请求的request级别存数据,产生的数据,随着请求关闭也就关闭了
- 因为,每个请求对于服务器来说,都是陌生的,
-
2.这样会带来问题,用户有需求:在浏览器中对服务器的多个请求数据能交互,比如购物车
-
3.这样就需要使用会话管理技术,借助Cookie或Session来记录请求状态,实现请求直接的会话交互
2. Cookie
2.1 Cookie原理解析
- 由服务器创建,并发送给浏览器,由浏览器保存,保存在浏览器端的一小块数据。
- 浏览器第一次访问服务器,服务器会给浏览器颁发一个凭证Cookie,通过响应头一并响应发给浏览器
- Cookie存放位置
- 默认情况,会存于浏览器中,浏览器关闭,Cookie也就情况
- 实际工作中,会设置Cookie生存时间,一旦设置,会保存在用户的硬盘内
- 一般会保存在本地的 用户目录下 appdata
- 携带有相同Cookie的浏览器请求,会被服务器识别
- 浏览器下次访问该服务器时,会在请求头部自动携带该块数据Cookie,将其发送给服务器进行验证
2.2 Cookie测试
返回类型设定
-
为测试显示方便,服务器向浏览器直接返回JSON字符串
- 只要向浏览器作出响应,都会将创建的携带Cookie
// Cookie测试 @RequestMapping(path = "/cookie/set", method = RequestMethod.GET) @ResponseBody public String setCookie(HttpServletResponse response){ return "set Cookie"; }
创建Cookie
new Cookie(“key”, “value”)
-
由服务端创建Cookie对象
- 测试中可以使用servlet中的类
-
一个Cookie只有一对健值对,且数据结构均为字符串
- 方便传送和识别
import javax.servlet.http.Cookie; // Cookie测试 @RequestMapping(path = "/cookie/set", method = RequestMethod.GET) @ResponseBody public String setCookie(HttpServletResponse response){ // 创建Cookie Cookie cookie = new Cookie("code", CommunityUtil.generateUUID()); return "set Cookie"; }
cookie.setPath("//alpha")
- 设置cookie生效的路径范围
- 即哪些路径下的请求可以有此Cookie凭证
- 注意,浏览器不能识别项目名,要将localhost:8080后面的所以上级路径都带上
- 即"/community/alpha",http://localhost:8080/community/alpha/下的所有路径
- 不能是"/alpha",表示http://localhost:8080/alpha/下的所有路径
cookie.setMaxAge(60 * 10)=
- cookie生存时间,以秒为单位
- 也是存储位置,默认浏览器内存,一旦设置,就会存储在硬盘
- 注意,默认服务器的时间都是世界时区
response.addCookie(cookie)
- 发送Cookie,添加进响应头,就会自动发送给浏览器
// Cookie测试
@RequestMapping(path = "/cookie/set", method = RequestMethod.GET)
@ResponseBody
public String setCookie(HttpServletResponse response){
// 创建Cookie
Cookie cookie = new Cookie("code", CommunityUtil.generateUUID());
// 设置Cookie
// 哪些路径下的请求可以有此Cookie凭证
cookie.setPath("/community/alpha");
// cookie生存时间,也是存储位置,10分钟
cookie.setMaxAge(60 * 10);
// 发送Cookie,添加进响应头,就会自动发送给浏览器
response.addCookie(cookie);
return "set Cookie";
}
测试结果
测试第二次访问携带cookie
- 只有cookie生效的范围路径才能携带cookie
@CookieValue(“code”)
-
如果用请求体,会获取很多cookie,不利于筛选,
- 用@CookieValue(“code”)注解获取指定key的cookie
-
服务端收到请求体中携带的cookie,可以有多种处理方式,以打印到控制台为例
// 测试请求中携带cookie @RequestMapping(path = "/cookie/get", method = RequestMethod.GET) @ResponseBody public String getCookie(@CookieValue("code") String code) { // 服务端获取到指定的cookie,有多种处理方式,以打印到输出台为例 System.out.println(code); return "get cookie"; }
测试结果
- 其他路径下的网页没有刚创建的key为code的cookie
- 指定范围内的请求会携带cookie
2.3 使用cookie优缺点
优点
- 储存在浏览器中,对服务器压力比较小,也避免了服务器分布式部署相关问题
缺点
- 不安全,因素储存在浏览器端,可以别查看到,易被盗用冒充
- 每次请求都发送cookie,对访问性能会有一定影响
3. Session
3.1 Session原理解析
- 由服务端创建,存储于服务端,并创建指定的cookie,key为指向session的seesionId
- 即,要结合cookie一块使用
- 响应给浏览器,会将key为sessionId的cookie传给浏览器保存
- 下次访问时,会查询浏览器请求携带的key为为sessionId的cookie,并查询验证session
- 这样,假设cookie被盗用,
- cookie中只是储存sessionId,无法获取session储存的内容,
- 查询到session后只能返回给原浏览器,不能响应给新的浏览器信息
3.2 Session测试
创建session
HttpSession
- 只要声明session,SpringMVC会自动识别、创建注入
- 类似于model
session.setAttribute(key, value)
-
也是设置健值对
-
但数据类型可以是任意,于cookie不同,因为cookie涉及到传输于识别问题
-
范围:默认当前项目下所有
-
时间:默认浏览器内存,当前会话生存级别,关闭浏览器,就会清空
扩展,不同内置对象的生命周期
从session中取值
session.getAttribute(key)
@RequestMapping(path = "/session/get", method = RequestMethod.GET)
@ResponseBody
public String getSession(HttpSession session) {
System.out.println(session.getAttribute("id"));
System.out.println(session.getAttribute("name"));
return "get session";
}
测试结果
- 默认当前域名下所有项目都会携带sessionID
100
test
session应用于分布式部署问题
问题提出
- 涉及多台服务器时,浏览器访问一个服务器1,当前服务器存session,
- 下次访问时,访问的是另一个服务器3,3中没有存session,就面临无法识别问题
不同解决策略对比
策略一:粘性session
- 即,一个浏览器就指定访问特定的一台服务器
- 这样,无法保证负载均衡
策略二:同步session
- 即,创建session的服务器会将session同步储存在其他服务器上
- 这样,每台服务器的负载压力都大,失去了分布式部署的初衷
策略三:共享session
- 即,设定一个专有服务器用来储存session
- 这样,万一这个服务器挂了,所有服务器均不能使用了
策略四:不使用session或是将session存NoSQL数据库中
- **即不使用session,对于不敏感的数据储存在cookie中**
- 对于敏感的数据将session储存在Nosql数据库中,数据库可以做成集群
- 传统的关系型数据库,读取磁盘操作比较满,因此影响性能
- 因此,改成储存在Nosql型数据库,即解决了以上问题,又能保证性能问题