2.3 会话管理

110 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

3. 会话管理

image-20220709160640704

Cookie和Session各有各的优点和缺点

1. Cookie

Cokie诞生原因

  • HTTP 是无状态,有会话的

HTTP 是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。而使用 HTTP 的头部扩展,HTTP Cookies 就可以解决这个问题。把 Cookies 添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。

注意,HTTP 本质是无状态的,使用 Cookies 可以创建有状态的会话

# HTTP Cookie

HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会
在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏
览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。

Cookie应用场景

Cookie 主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie 曾一度用于客户端数据的存储,因当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。由于服务器指定 Cookie 后,浏览器的每次请求都会携带 Cookie 数据,会带来额外的性能开销(尤其是在移动环境下)。新的浏览器 API 已经允许开发者直接将数据存储到本地,如使用 Web storage API (本地存储和会话存储)或 IndexedDB

cookie优缺点

优点:可以解决HTTP 无状态的问题

缺点:Cookie存在在客户端,可能会造成隐私泄露;

​ 另外浏览器每次发送给服务器Cookie会对流量产生影响

image-20220709170520005

当浏览器发送cookie给服务器时,服务器接收cookie以后可能取里面的值用一下,或者在模板里用一下。

演示cookie

通过上面的文字,相信我们对 Cookie 已经有了简单的认识,下面写几个简单的小例子体会一下相关语法。

因为只是简单的小例子,不是什么业务,所以写到 AlphaController里,这里装着一些演示的小demo。

@Controller
@RequestMapping("/alpha")
public class AlphaController {
  
    // cookie 示例
    @RequestMapping(path = "/cookie/set", method = RequestMethod.GET)
    @ResponseBody
    public String setCookie(HttpServletResponse response){
        // 创建cookie,必须传入参数(没有无参构造器),且必须都是字符串
        // 并且每一个cookie对象只能存一组字符串,即一个key-val
        Cookie cookie = new Cookie("code", CommunityUtil.generateUUID());

        // 设置cookie生效的范围,服务器首先发送给浏览器cookie,然后浏览器给服务器发请求需要发cookie
        //需要指定浏览器给服务器的哪些路径请求发cookie,不必每个路径都发,因为可能不需要,会浪费网络资源
        cookie.setPath("/community/alpha");     // 设置cookie只有在这个路径及子路径才有效

        // cookie默认发到浏览器,浏览器关掉就消失
        // 一旦给cookie设置了生存时间,它会存在硬盘里,长期有效,直到超过这个时间才会无效
        // 设置cookie的生存时间
        cookie.setMaxAge(60 * 10);      // 单位是秒

        // 将cookie放到response头里发送
        response.addCookie(cookie);

        return "set cookie";
    }
    @RequestMapping(path = "/cookie/get", method = RequestMethod.GET)
    @ResponseBody
    // @CookieValue("code")是获取cookie中key为"code"的value
    // cookie需要在服务器和客户端之间传,所以只能存少量,另外客户端可以识别字符串,其他java类型无法识别,所以用key-value
    public String getCookie(@CookieValue("code") String code){
        System.out.println(code);
        return "get cookie";
    }

}

image-20220709173158401

测试:

首先浏览器访问Controller的cookie/set方法,可以看到请求里面没有cookie,但是响应里面有cookie

image-20220710091846754

然后浏览器访问Controller的cookie/get方法可以看到请求里面也有了cookie

image-20220710092158068

2. Session

Sesson定义

是JavaEE的标准,用于在服务端记录客户端信息。

注:Session本质是依赖于cookie的,浏览器和服务器之间是多对一的关系,浏览器和Session之间的对应关系怎么找是依赖于cookie的(将sessionId存到cookie里发送)。

image-20220710084412634

Session 优缺点

优点:

​ 可以解决http无状态的问题

​ 数据存放在服务器更加安全

缺点:

​ 数据存放在服务器会增加服务器的压力

演示Session

@Controller
@RequestMapping("/alpha")
public class AlphaController {
  

    // session 示例
    @RequestMapping(path = "/session/set", method = RequestMethod.GET)
    @ResponseBody
    public String setSession(HttpSession session){
        // session 创建不需要我们手动创建,SpringMVC会自动创建session并帮我们注入进来,所以只需声明即可
        // session 是一直存在在服务端的,所以它里面存什么数据都可以
        session.setAttribute("id", 1);
        session.setAttribute("name", "Test");
        return "set session";
    }

    @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";
    }
}

image-20220710092907718

image-20220710092943403

3. 分布式使用Session存在什么问题,解决方案是什么

访问分布式中之前没访问过的服务器时,服务器里面没有存在之前的session,浏览器得不到之前的session

  1. 解决:黏性session,对于一个固定ip的请求,固定分给一个服务器处理。 缺点:分布式本来是解决负载均衡问题的,这种解决方法会导致负载不均衡问题。

image-20220710094632034

  1. 解决:同步session,某一个服务器创建session并且存了数据之后,它会把这个session同步给其他的服务器 缺点:这种方法会对服务器性能产生一定的影响;服务器和服务器之间有了一定的关系,产生耦合,之间不是那 么的独立了。

image-20220710094714759

  1. 解决:共享session,搞一台共享服务器,这个服务器不是处理业务的,而是专门用来存session的, 其他服务器都向这台服务器获取session, 缺点:如果共享session服务器宕机了,其他服务器都没办法工作了。

image-20220710095139354

目前解决方案,能存到cookie就存到cookie,不能存到cookie的数据就存到关系型数据库里,数据库的数据存在硬盘里,存取比较慢,性能慢。但是存到 非关系型数据库NoSQL比如redis就快很多了

image-20220710095643897

我们在前面开发的时候会话数据先存到数据库或者session(不适合存到mysql里的先存到session)里,在后面学习了redis之后的再迁移到redis里