第二篇:koa2-web应用进阶—session

本文将介绍koa web应用中的session使用, Session 对象可以用于存储特定用户会话所需的属性及配置信息, 例如用户的登入信息。

一、中间件选择

1、从koa wiki中可以发现koa的session中间件多大12种,但是目前大都未支持koa2。对于未支持koa2的中间件,可以应如中间件 koa-convert 包裹后在koa2中使用。
2、为了获得koa2更好的支持,本文选择中间件 koa-session2

二、简单实现

在第一篇的koa web应用基础上进行配置,为了延续之前不使用 async/await的原则,我们选用不需要babel转码的版本, 但 node 版本必须为 6.x
1、 加入依赖: npm install –save koa-session2@node6

  • 2、 **加入session配置代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const Koa = require('koa')
const co = require('co')
const nunjucksViews = require('koa-nunjucks-promise')
const router = require('koa-router')
const mount = require('koa-mount')
const server = require('koa-static')
const session = require("koa-session2")
const app = new Koa()
const route = new router()
app.use(nunjucksViews(`${__dirname}/views`, { //配置模板文件路径,
ext: 'html', //渲染文件后缀为 html
noCache: true, //开发环境下不设置缓存
watch: true, //开发环境下观察模板文件的变化并更新
filters: { //过滤器
json: function(str) {
return JSON.stringify(str, null, 2)
}
},
globals: { //设置对于nunjucks的全局变量
// staticPath: '//static'
}
}))
app.use(mount('/static', server(`${__dirname}/public`))) //设置静态文件路径

//--------------------------------------
app.use(session({
key: "SESSIONID", //default "koa:sess"
maxAge: 5000 //设置session超时时间
}))
route.get('/', co.wrap(function* (ctx) {
if(ctx.session.view === undefined) { //统计访问次数
ctx.session.view = 0
} else {
ctx.session.view += 1
}
console.log('viewNum', ctx.session.view) //log 输出
yield ctx.render('index', {title: 'Nunjucks', content: 'Feifeiyu yeah!'})
}))
//--------------------------------------------
route.get('/route/test', co.wrap(function* (ctx) {
ctx.body = 'feifeiyu nuaa'
}))
app.use(route.routes())
.use(route.allowedMethods())
app.listen(3000, () => console.log('server started, port 3000'))
module.exports = app

3、 启动服务, 访问 http://localhost:3000/, 以chrome为例:打开浏览器调试工具, 打开: Resources => Cookies => localhost,可以看见 session 相关信息: 例如,SESSIONID就是代码中配置的key字段
session
4、 console中打印的信息: 页面每刷新一次, viewNum 加 1, 即代表访问页面一次; 间隔五秒钟后刷新, viewNum 清空,说明上一个session已失效,重新生成新的session
session

##session redis##
在上例中,生产的sessio都是存储在node进程开辟的内存中,除此之外,session还可以存储在缓存(redis),数据库(mongodb, mysql)等数据管理工具中。本篇介绍将session如何存储在redis中
1、引入依赖: 1、推荐redis client中间件 ioredis , ioredis优势在于支持es6的promise对象。 npm i –save ioredis。 2、npm i –save uid-safe, 用于redis 存储key (sessionid) 的生成
2、根据 koa-session2 git README.md Options中描述 {a class for custom store (extend {Store}, func: #get(sid), #set(session, opts), #destory(sid))}, 需要重写下 store 这个类. 在 README 中提供了相关的例子(Custom Stores),好像这个例子在写redis时数据格式不对,无法正确存储。因此我们参考例子 “Custom Stores” 和 “koa-session2/libs/store.js” 这两个类,重写下 store类,完成 redis 中 session 的 存(set), 取(get), 销毁(destroy)
3、 在工程目录下新建文件 store.js, 在store.js中加入如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
'use strict'
const redis = require('ioredis')
const uid = require('uid-safe')
class Store {
constructor() {
this.redis = new redis() //默认 127.0.0.1 6379端口
}
getId(length) {
return uid.sync(length) //生成id
}
get(sid) { //实现get方法
return this.redis.get(`session-${sid}`).then((resp) => {
try { //如果返回结果不是json字符串,返回空
return Promise.resolve(JSON.parse(resp))
} catch(e) {
return Promise.resolve({})
}
})
}
set(session, opts) { //实现set方法
if(!opts.sid) {
opts.sid = this.getId(24)
}
//存入redis要将对象转成JSON字符串
//存入redis的key为: session-uid
return this.redis.set(`session-${opts.sid}`, JSON.stringify(session)).then(() => {
return Promise.resolve(opts.sid)
})
}
destroy(sid) { //实现distroy方法
return this.redis.del(`session-${sid}`)
}
}
module.exports = Store

4、 app.js 中为 session 添加配置项 store:

1
2
3
4
5
6
7
8
9
10
11
12
const store = require('./store') //引入上面写的 store类
//----------
code...
//----------
app.use(session({
key: "sessionId", //default "koa:sess",
store: new store(), //添加 store 配置项
maxAge: 5000 //设置session超时时间
}))
//----------
code...
//----------

5、 首先要在本机启动redis 服务 redis安装 debian, redis 启动: redis-server & (加 & 表示在后台运行)
6、 启动koa web 服务,按照上例的步骤执行,可以观察到相同的结果, 在store 所在目录会生产一个dump.rdb文件
7、 如果想换成其他的数据存储工具, 只需要将 store 这个类修改成对相应数据存储工具的访问即可