1. 概念:
- 是一个数据对象,用来存储信息。
- 是一个抽象对象,指代多个有关联的http请求所构成的一个会话。多次请求之间能够共享一些信息。
2. 实现方案:
- 方案1:在每个请求的参数或者数据中带上相关的信息。不受 cookie 限制,但是受到 请求长度的限制。
- 方案2:用 cookie 存储,可以是整个session 的具体数据,也可以是 session的标识(sessin_id).
3. 特点:
- 只存在于 服务端。
- 并不是 服务器 原生支持的。是中间件自己创建并管理的。
- session 仅仅是一个对象信息,可以存到 cookie ,也可以存到任何地方(如内存,数据库)。
- 存到哪,可以开发者自己决定。
- session_id,是唯一的标识 session 的,以及其他一些必要信息会放在 cookie 中,一起返回到前端。
- 其他信息,可以保存在 session_id 命名的文件中。
4. session 的负面影响:
- 性能影响。如果用户很多,信息都保存在 sessin 文件中,查找耗时太多(可以分目录和哈希等)。
- 可以自己实现session,将session信息存放到 数据库当中,这样做最好对数据库进行一下缓存的设置了,不然对上千万的数据进行太频繁的检索,也是蛮耗资源的。
5. session 的清除:
- 定期清理 session(清除服务端的 session 文件,和 客户端的 cookie 信息)
- cookie, expires 设置为 过去的时间/max-age = 0,客户端的cookie 信息就会过期,浏览器就会自动删除。
6. koa-session 的 原理:
- 【有空一定要看看源码,看源码要注意命名、特色、知识点的学习。也会学习 koa 插件的写法的过程】【看源码,要先有整体把控图,然后逐步去分析啊】
-
使用流程:
- app.use(session(CONFIG, app)); // 初始化koa-session中间件
- let n = ctx.session.views || 0; // 每次都可以取到当前用户的session
- 初始化的时候,把 session 对象挂载在 app.context上。所以后面可以 从 ctx.session 上获得 session
- 在接到 http 请求的时候,
- 默认把数据 json ,塞进了 cookie ,即 cookie 来存储加密后的 session 信息。
- 如果设置了外部 store ,会调用 store.set() 去保存 session 。具体的保存逻辑,保存到哪里,由 store 对象自己决定!
- 用 cookie 存储的时候,对session(包含过期时间)序列化后做一个简单的base64编码。
- 就算信息保存在文件中,还是必不可少的需要 cookie
- session_id 的默认实现是 一个时间戳加随机字符串。
- koa-session允许用户在config中配置自己的编码和解码函数,因此完全可以使用自定义的加密解密函数对session进行编解码
7. session 的鉴权过程:
- 用户登录的时候,服务端生成一个会话和一个id标识
- 会话id在客户端和服务端之间通过cookie进行传输
- 服务端通过会话id可以获取到会话相关的信息,然后对客户端的请求进行响应;如果找不到有效的会话,那么认为用户是未登陆状态
- 会话会有过期时间,也可以通过一些操作(比如登出)来主动删除
8. 分布式 session:
-
问题:分布式环境下,前后访问的服务器不同,所以导致 session 不能准确保存
- 解决方案:将 session 信息放在一个独立的机器上(可以是一个独立的数据库服务,也可以是一个缓存服务)
- 缺点:但是这个持久层一旦挂了,就会单点失败。
- 新方案:索性不保存session 数据,所有数据保存在客户端,每次请求都发回服务器(这就是 token)
9. cookie 和 session 的区别:
- 存储位置不同:cookie -> 客户端浏览器。session -> 服务器
- 隐私策略不同:cookie -> 不是很安全,cookie 劫持。session -> 相对安全
- 性能不同:session -> 访问量太大时,占用服务器性能
- 存储大小不同:cookie -> 有大小限制,一般不超过4K
10. 使用session需要考虑的问题
- 将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session 会占据较多的内存,需要在服务端定期的去清理过期的 session
- 当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建 session 的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。
- 当多个应用要共享 session 时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。
- sessionId 是存储在 cookie 中的,假如浏览器禁止 cookie 或不支持 cookie 怎么办?一般会把 sessionId 跟在 url 参数后面即重写 url,所以 session 不一定非得需要靠 cookie 实现
- 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
11.分布式架构下 session 共享方案
1. session 复制
- 任何一个服务器上的 session 发生改变(增删改),该节点会把这个 session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 session ,以此来保证 session 同步
优点:可容错,各个服务器间 session 能够实时响应。
缺点:会对网络负荷造成一定压力,如果 session 量大的话可能会造成网络堵塞,拖慢服务器性能。
2. 粘性 session /IP 绑定策略
- 采用 Ngnix 中的 ip_hash 机制,将某个 ip的所有请求都定向到同一台服务器上,即将用户与服务器绑定。用户第一次请求时,负载均衡器将用户的请求转发到了 A 服务器上,如果负载均衡器设置了粘性 session 的话,那么用户以后的每次请求都会转发到 A 服务器上,相当于把用户和 A 服务器粘到了一块,这就是粘性 session 机制。
优点:简单,不需要对 session 做任何处理。
缺点:缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 session 信息都将失效。
适用场景:发生故障对客户产生的影响较小;服务器发生故障是低概率事件。实现方式:以 Nginx 为例,在 upstream 模块配置 ip_hash 属性即可实现粘性 session。
3. session 共享(常用)
- 使用分布式缓存方案比如 Memcached 、Redis 来缓存 session,但是要求 Memcached 或 Redis 必须是集群
- 把 session 放到 Redis 中存储,虽然架构上变得复杂,并且需要多访问一次 Redis ,但是这种方案带来的好处也是很大的:
- 实现了 session 共享;
- 可以水平扩展(增加 Redis 服务器);
- 服务器重启 session 不丢失(不过也要注意 session 在 Redis 中的刷新/失效机制);
- 不仅可以跨服务器 session 共享,甚至可以跨平台(例如网页端和 APP 端)
4. session 持久化
- 将 session 存储到数据库中,保证 session 的持久化
优点:服务器出现问题,session 不会丢失
缺点:如果网站的访问量很大,把 session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。
只要关闭浏览器 ,session 真的就消失了?
不对。对 session 来说,除非程序通知服务器删除一个 session,否则服务器会一直保留,程序一般都是在用户做 log off 的时候发个指令去删除 session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分 session 机制都使用会话 cookie 来保存 session id,而关闭浏览器后这个 session id 就消失了,再次连接服务器时也就无法找到原来的 session。如果服务器设置的 cookie 被保存在硬盘上,或者使用某种手段改写浏览器发出的 HTTP 请求头,把原来的 session id 发送给服务器,则再次打开浏览器仍然能够打开原来的 session。恰恰是由于关闭浏览器不会导致 session 被删除,迫使服务器为 session 设置了一个失效时间,当距离客户端上一次使用 session 的时间超过这个失效时间时,服务器就认为客户端已经停止了活动,才会把 session 删除以节省存储空间。
12. 参考:
- https://www.cnblogs.com/woodk/p/10129836.html
- 看源码的时候,可以画一下 主要模块的脑图,更有助于理解。
- https://www.cnblogs.com/longhao/p/3558871.html
- https://www.jianshu.com/p/8f4cc45d712e
- https://segmentfault.com/a/1190000013039187
- https://juejin.im/post/59d1f59bf265da06700b0934#heading-9
- https://juejin.im/post/5d01f82cf265da1b67210869#heading-11
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。