谁说Session只能存储在服务器端?

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 今天使用Koa遇到了一个诡异的问题,然后仔细研究了Koa-Session的实现原理,刷新了我的认知。好我们从头讲起。 先看看Session的原理是什么?

Session是什么


session机制采用的是一种在服务器端保持状态的解决方案。由于采用服务器端能保持状态。也需要客户端保存一个标识。所以session机制可能需要借助于cookie机制来达到保存标识的目的。


网络异常,图片无法展示
|


  1. 服务器在接受客户端首次访问时在服务器端创建seesion,然后保存seesion(我们可以将seesion保存在内存中,也可以保存在redis中,推荐使用后者),然后给这个session生成一个唯一的标识字符串,然后在响应头中种下这个唯一标识字符串。


  1. 签名。这一步通过秘钥对sid进行签名处理,避免客户端修改sid。(非必需步骤)


  1. 浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,浏览器在下次http请求的请求头中会带上该域名下的cookie信息,


  1. 服务器在接受客户端请求时会去解析请求头cookie中的sid,然后根据这个sid去找服务器端保存的该客户端的session,然后判断该请求是否合法。


如果按照经典实现的方式,session数据是保存在服务器端的,那么假设session不使用外部存储设备,session也就是存储在内存中的。那么如果一旦服务器重新启动所有session就会消失。


诡异的Koa-session


好那么我们看看Koa-Session是不是可以复现这个问题。


const koa = require('koa')
const app = new koa()
const session = require('koa-session')
// 签名key keys作用 用来对cookie进行签名
app.keys = ['some secret'];
// 配置项
const SESS_CONFIG = {
  key: 'kkb:sess', // cookie键名
  maxAge: 86400000, // 有效期,默认一天
  httpOnly: true, // 仅服务器修改
  signed: true, // 签名cookie
};
// 注册
app.use(session(SESS_CONFIG, app));
// 测试
app.use(ctx => {
  if (ctx.path === '/favicon.ico') return;
  // 获取
  let n = ctx.session.count || 0;
  // 设置
  ctx.session.count = ++n;
  ctx.body = '第' + n + '次访问';
});
app.listen(3000)


网络异常,图片无法展示
|


按照程序功能变量count每次都会累加,如果重新启动服务。count应该归零。但是结果确不是这样。


网络异常,图片无法展示
|


网络异常,图片无法展示
|


原因分析


这时候我们细致的分析一下。首先我么发现在这里存储sid的cookie字段的值是eyXXXXX这样的一个值。说明很可能是base64编码的json。不是我们通常认为的uuid。


网络异常,图片无法展示
|


通过在线的base64解码我们确认了这个结果。


网络异常,图片无法展示
|


这样问题就很清晰了。原来Koa-session默认确实是通过将session序列化后存储在客户端的。 我们从以下的npm文档中也可以证实了这个说法。


www.npmjs.com/package/koa…


网络异常,图片无法展示
|


文档里明确声明koa默认存储是放在客户端的非加密数据。


客户端存储的优缺点分析


优点


首先先说优点。客户端存储的优点大概有两个。


  • 低成本的实现了session的持久化问题


  • 低成本的实现了多实例共享session问题


通常情况下我们如果实现session的持久化和全局共享都需要使用第三方存储比如redis或者mongodb。client端序列化方式就很好的解决了这个问题。但是使用客户端存储就很好的解决了这个问题。


缺点


缺点也有两条


  • 存储容量有限制(Cookie 大小一般是4k)


  • 安全性问题由于存储在客户端而且是非加密数据所以不能存储敏感数据。


如何指定存储方式


在Koa-Session中如果希望变更存储方式可以通过实现store接口的方式实现。


内存实现


首先我们先写一个基础的内存实现。其实就是为了熟悉一下这个接口。


class Memory {
    constructor () {
        this.sotry = {}
    }
    get(key) {
        console.log('get:',key)
        return this.sotry[key]
    }
    set(key,sess) {
        console.log('set:',key,sess)
        this.sotry[key] = sess
    }
    destroy (key) {
        console.log('destroy:',key)
        this.sotry = {}
    }
}
const SESS_CONFIG = {
    key: 'kkb:sess', 
    store: new Memory() // 指定实现
}
app.use(session(SESS_CONFIG, app))


可以看到指定了存储后,koa-session会调用存储接口中的getter和setter方法。


网络异常,图片无法展示
|


浏览器中也不会存储序列化数据而是只存储sid也就是uuid。


网络异常,图片无法展示
|


完整代码


github.com/su37josephx…


Redis实现


另外我们再看看生产环境中常用的Redis存储方式。


const redisStore = require('koa-redis')
const redis = require('redis')
const redisClient = redis.createClient(6379, 'localhost')
const wrapper = require('co-redis')
const client = wrapper(redisClient)
app.keys = ['some secret']
const SESS_CONFIG = {
    key: 'kkb:sess', // 名
    store: redisStore({ client })
}
app.use(session(SESS_CONFIG, app))


总结


Koa的默认存储方式选择的是客户端序列化方式,刷新了我们对Session常规的印象。这种方式其实借鉴了JWT Token的实现方法。非常适合小型应用。可以很低成本的解决持久化和横向扩展问题。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
打赏
0
0
0
0
2
分享
相关文章
服务器数据恢复—EMC存储raid5阵列数据恢复案例
服务器存储数据恢复环境: EMC某型号存储中有一组由8块硬盘组建的raid5磁盘阵列。 服务器存储故障: raid5阵列中有2块硬盘离线,存储不可用,上层应用崩了。
服务器数据恢复—EqualLogic存储硬盘出现坏道的数据恢复案例
一台EqualLogic某型号存储中有一组由16块SAS硬盘组建的RAID5阵列。上层采用VMFS文件系统,存放虚拟机文件,上层一共分了4个卷。 磁盘故障导致存储不可用,且设备已经过保。
|
2月前
|
Dell OpenManage Enterprise 4.4 - Dell 服务器、存储和网络设备集中管理软件
Dell OpenManage Enterprise 4.4 - Dell 服务器、存储和网络设备集中管理软件
69 4
Dell OpenManage Enterprise 4.4 - Dell 服务器、存储和网络设备集中管理软件
阿里云服务器ECS计算型c7和通用算力型u1在适用场景、计算性能、网络与存储性能等方面的对比
阿里云ECS服务器u1和c7实例在适用场景、性能、处理器特性等方面存在显著差异。u1为通用算力型,性价比高,适合中小企业及对性能要求不高的场景;c7为企业级计算型,采用最新Intel处理器,性能稳定且强大,适用于高性能计算需求。u1支持多种CPU内存配比,但性能一致性可能受底层平台影响;c7固定调度模式,确保高性能与稳定性。选择时可根据预算与性能需求决定。
128 23
阿里云服务器付费类型、地域、镜像、存储、带宽和安全组设置与选择注意事项参考
在我们通过自定义购买的方式购买阿里云服务器器ECS时,会有多个选项,有的新手用户可能并不是很清楚这些选项是什么,选择或设置时需要注意什么,本文将从付费类型、地域与可用区、镜像、存储、带宽和安全组等多个方面,为您详细解析云服务器购买过程中各个参数与配置的选择注意事项,以供参考。
326 66
服务器数据恢复—V7000存储上raid5阵列多块硬盘离线的数据恢复方案
V7000存储设备上raid5阵列上一块硬盘出现故障离线,热备盘自动启用开始同步数据。热备盘数据同步还没有结束的情况下,与离线盘处于同一组Mdisk中的另一块磁盘离线。热备盘同步失败,该组Mdisk失效,通用卷无法使用。
服务器数据恢复—EMC UNITY 400存储卷被误删除的数据恢复案例
EMC Unity 400存储连接了2台硬盘柜。2台硬盘柜上一共有21块硬盘(520字节)。21块盘组建了2组RAID6:一组有11块硬盘,一组有10块硬盘。 在存储运行过程中,管理员误操作删除了 2组POOL上的部分数据卷。
服务器数据恢复—nas中raid6阵列失效,存储无法访问的数据恢复案例
一台nas上共有14块硬盘组建了一组raid6磁盘阵列。 该nas在工作过程中,raid6阵列中硬盘出现故障离线,导致raid6阵列失效,nas无法正常访问。
服务器数据恢复—OceanStor存储数据恢复案例
华为OceanStor T系列某型号存储中有一组由24块机械硬盘组建的一组RAID5阵列。 运行过程中该存储设备RAID5阵列上多块硬盘出现故障离线,阵列失效,存储中数据无法访问。
服务器数据恢复—EVA存储硬盘读写性能不稳定掉线的数据恢复案例
服务器存储数据恢复环境: 一台EVA某型号控制器+EVA扩展柜+FC磁盘。 服务器存储故障&检测: 磁盘故障导致该EVA存储中LUN不可用,导致上层应用无法正常使用。
154 47

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问