1. session背景知识:
session也被称为“会话控制”,顾名思义,它用于控制网络会话,如用户登录信息、购物车中的商品。
session中的数据是保存在服务器端的,在服务器端有很多种存储方式,既可以直接保存在内存中,也可以保存在Redis、MongoDB、Mysql等数据库中。但是session中的数据一般都是在短时间内高频访问的,需要保证性能(在内存中缓存,读写快),同时这样容易丢失数据,如遇到服务器重启的情况。因此比较好的方式是内存缓存配合外部数据库对session做一个持久化,方便丢失数据后的数据找回。
2. 将用户session信息持久化:
在Koa中有不少中间件提供了session数据的持久化功能,这里我通过两种方法来实现,大家根据自己的需求来取用:
(1). 将session存放在Mysql数据库中
需要用到中间件:
koa-session-minimal
适用于koa2 的session中间件,提供存储介质的读写接口 。
koa-mysql-session
为koa-session-minimal
中间件提供Mysql数据库的session数据读写操作。
示例代码:
const Koa = require('koa')
const session = require('koa-session-minimal')
const MysqlSession = require('koa-mysql-session')
const app = new Koa()
// 配置存储session信息的mysql
let store = new MysqlSession({
user: 'root',
password: 'yourpassword',
database: 'app_database',
host: '127.0.0.1',
})
// 存放sessionId的cookie配置,根据情况自己设定
let cookie = {
maxAge: 20*60*1000, // cookie有效时长(ms)
expires: '', // cookie失效时间
path: '', // 写cookie所在的路径
domain: '', // 写cookie所在的域名
httpOnly: true, // 是否只用于http请求中获取
overwrite: true, // 是否允许重写
secure: '',
sameSite: '',
signed: true,
}
// koa-session-minimal需要一个options对象参数:
/***
* key:会话cookie名称和商店密钥前缀
store:会话外部存储
cookie:cookie选项,可以是对象(静态cookie选项)或返回对象的函数(动态cookie选项)。
只有maxAge,path,domain,secure,httpOnly是支持的。
*/
app.use(session({
key: 'SESSION_ID',
store: store,
cookie: cookie
}))
//下面就可以在自己的路由中间件中来定义session信息了
//每次请求路由接口,都会对session信息进行更新,请自行验证
app.use( async ( ctx ) => {
// 设置session
if ( ctx.url === '/set' ) {
ctx.session = {
user_id: Math.random().toString(36).substr(2),
count: 0
}
ctx.body = ctx.session
} else if ( ctx.url === '/' ) {
// 读取session信息
ctx.session.count = ctx.session.count + 1
ctx.body = ctx.session
}
})
app.listen(3000)
console.log('[demo] session is starting at port 3000')
查看数据库,多了一个_mysql_session_store
表:
(2). 将session存放在Redis中:
需要用到的中间件
redis
koa-redis
koa-session-minimal
示例代码:
const session = require('koa-session-minimal');
const redisStore = require('koa-redis');
const Koa = require('koa');
const redis = require('redis');
//实例化redis数据库,并连接,生成redis客户端对象
const client = redis.createClient(6379, "127.0.0.1");
const app = Koa ();
app.keys = ['keys', 'keykeys'];
const options = {client: client, db: 1};
const store = redisStore(options);
app.use(session({
key: 'SESSION_ID',
store: store,
cookie: cookie //与上面的示例代码的参数一样
}));
//以上是为session的外部存储配置了redis的一个客户端,不像前面的koa-mysql-session,
//已经封装了存入session的操作,这里需要在不同的路由中间中通过store.client对象
//的一些原生方法对session数据进行向redis的增删改查
app.use(function *() {
switch (this.path) {
case '/get':
get.call(this);
break;
case '/testKV':
// 保存key value
if (this.query.adminId) {
yield store.client.set("test1", this.query.adminId);
}
//同步读取key value
this.body = yield store.client.get("test1");
break;
case '/testHM':
//操作hashmap
var result = yield store.client.hmset("hosts", "mjr", "123", "another", "23", "home", "1234");
console.log(result);
var obj = yield store.client.hgetall("hosts")
console.dir(obj);
//获取hashmap key的值
this.body = yield store.client.hget("hosts", "home");
break;
case '/testSet':
//保存set
var key = "key1";
store.client.sadd("key1", "v1");
store.client.sadd("key1", "v2");
store.client.sadd("key1", "v3");
//读取set
store.client.multi()
.sismember(key, 'v1')
.smembers(key)
.exec(function (err, replies) {
console.log("MULTI got " + replies.length + " replies");
replies.forEach(function (reply, index) {
console.log("Reply " + index + ": " + reply.toString());
});
});
//读取set
this.body = yield store.client.smembers("key1");
break;
case '/testList':
//保存list
store.client.rpush("mylist", "bbb")
store.client.rpush("mylist", "ccc")
store.client.lpush("mylist", "aaa")
this.body = yield store.client.rpop("mylist");
break;
case '/remove':
remove.call(this);
break;
case '/regenerate':
yield regenerate.call(this);
break;
}
});
function get() {
var session = this.session;
session.count = session.count || 0;
session.count++;
var test = store.client.get("test");
console.log(test);
this.body = session.count;
}
function remove() {
this.session = null;
this.body = 0;
}
function *regenerate() {
get.call(this);
yield this.regenerateSession();
get.call(this);
}
app.listen(8080);
以上是将session信息持久化到mysql和redis中的具体代码,发送回浏览器的cookie信息还是会在指定失效时间失效,只是在过期之前一旦发生session数据的意外丢失,可以通过mysql或redis对session的存储来恢复数据。