实现session存储在redis中
- 基于koa-generic-session和koa-redis
- koa-redis是基于redis的,所以必须安装redis
- 在app.js中使用session中间件时,在session中间件内配置redis,则不需手动将session存储在redis内,直接将username等信息存储在session内即会同步到redis内
安装插件
安装插件koa-generic-session和koa-redis(koa-redis是基于redis的,所以必须安装redis):
1 | npm i koa-generic-session koa-redis redis --save |
app.js使用插件 配置session和redis
- app.js中引入插件:
- app.js中,在routes前使用插件配置session和redis:
app.keys
即我们之前配置过的密匙,这里就用原来的,也可以是更复杂的- session数据是放在服务端的,cookie数据则存放在客户的浏览器上
- path:可使用cookie的路由
- httpOnly:true时前端js无法访问cookie
- maxAge:cookie有效时间(毫秒)
- 先把redis的配置环境写死,实际应该本地配置本地,线上配置线上
- 配置好后,每次用户发送http请求时,都会根据用户请求中的cookie到redis中获取session数据
routes-user.js验证
- routes-user.js中,添加一个测试路由:
- 运行redis(redis安装目录下打开cmd,运行
redis-server.exe redis.windows.conf
启动redis) - 运行项目,访问测试路由http://localhost:8000/api/user/session-test:![访问测试路由](https://i0.wp.com/ww1.sinaimg.cn/large/005H7IVsgy1gdk3fwjoanj31c9089gn0.jpg)
- viewConut为访问次数,同一个浏览器多次访问会累加访问次数,但只存储一次session
- 查看是否存在redis中:redis目录下另启一个 cmd 窗口,原来的不要关闭(否则无法访问服务端),运行
redis-cli
后看到目前设置的所有key(keys *
):
回顾session和cookie
- 首先cookie是一个对象,里面存储的是userId、path等;session也是一个对象,其中存储的是username和password等。
- cookie是存储在浏览器上的,session则可以存储在node中作为js变量或者存储在redis中。
- 流程总结:
- 用户登录网页,在登录路由中将输入的username等数据放入session中,并使用redis的set方法将session数据同步存储到redis中
- 接下来每次访问网页时,首先执行的app.js就会根据用户请求中的cookie的userId,使用redis解析(读取)session得到username等数据,以此判断用户是否登录。
开发路由
项目安装mysql
npm i mysql xss --save --registry=https://registry.npm.taobao.org
复用blog-1中部分代码
- 统一数据返回格式:将blog-1中的model整个文件夹拷贝到blog-koa2文件夹下
- 数据库配置信息:将blog-1中的conf整个文件夹拷贝到blog-koa2文件夹下
- 在blog-koa2的app.js中引入conf中关于redis的配置信息,修改之前写死的redis配置:
- 新建db文件夹,将blog-1中的db文件夹下的mysql.js拷贝过来。
- 拷贝controller整个文件夹,进行修改:
- 按照async语法 修改blog.js:在每个函数前面添加async,返回值使用await关键词:await处理Promise对象会直接得到resolve状态下返回的值,这样就没有Promise异步的问题了
- blog.js中,async中遇到then时可这样修改:
- 修改user.js:
- user.js中需要用到cryp.js,所以拷贝blog-1中的utils文件夹下的cryp.js
- 一样按照async语法修改user.js:
- 按照async语法 修改blog.js:在每个函数前面添加async,返回值使用await关键词:await处理Promise对象会直接得到resolve状态下返回的值,这样就没有Promise异步的问题了
创建 中间件(登录校验)
- 新建middleware文件夹:
- 新建loginCheck.js文件,一样是判断session中是否有username,有则认为已登录,继续执行下一个中间件,没有则返回“未登录”:
开发博客路由(routes-blog.js)
- list路由:
- detail路由:
- new路由:
- update路由:
- del路由:
- 给需要的路由添加登录校验:
开发用户路由(routes-user.js)
- 一样引入需要使用的:
- login路由:koa2框架中,app.js中我们时候用session中间件时配置了redis,故不需手动存储session到redis中
前端联调
- 运行前后端项目,前端运行在8001端口,后端运行在8000端口:
- 运行nginx和redis
- 测试所有功能:
- (未登录)进入首页就会产生一个和cookie的id:此时session并未存储到redis中
- 进入登录页,登录zhangsan帐号后,产生另一个id,这个id会存储在session中:
- 存储在redis中的cookie对应的session的内容:
- 接下来每次发送的请求进入app.js后就会根据cookie进入redis中读取对应的session,通过session中的username来判断用户登录与否
日志
- 现在只讲使用koa-morgan插件记录access log并写入文件
- 自定义日志先使用console.log和console.error即可,至于如何写入文件等后面再讲
记录access log
- 新建logs文件夹用于存放日志-新建access.log文件用于存放访问日志
- koa2框架中自带的koa-logger插件起一个开发环境下规范打印格式的效果,比如:
- 但koa-logger插件只是美化打印效果,并不能用于记录access log
koa-morgan插件
- 这里我们需要使用express框架的morgan插件来记录access log
- 但morgan只支持express框架,所以需要先做一个兼容,通过koa-morgan来安装,使其可以运行在koa2开发环境中:
- morgan插件的使用方法:
morgan(参数1,参数2)
- **参数1**:(字符串)可选
'dev'
/'combined'
等,决定log字符串格式- 比如,一般开发环境下选择dev:线上环境则选择完善一点的格式combined
- 参数2:可省略
- 默认为
{stream:process.stdout}
,即通过stream(流)的 打印在控制台上显示; - 可以是
{stream:process.写入文件的stream对象}
,即 将log写入文件(写入文件的stream对象 可参考这篇笔记)
- 默认为
- **参数1**:(字符串)可选
- 在app.js中:
- 需要写入文件就需要引入path和fs,需要记录access log就需要引入koa-morgan:
- 测试:
- 先测试开发环境:
- 再测试线上环境:
- package.json中,由于我们还没学pm2,先改nodemon:
- 运行线上环境:
- 访问几次不同的页面,可看到access.log中已有日志:
自定义日志
- 自定义日志先使用console.log和console.error即可,至于如何写入文件等后面再讲
- 比如,在routes-blog.js中,自定义日志:
- 效果:
koa2中间件原理
- 可参考koa官网
- app.use()用于注册中间件
- next机制:即上一个中间件通过next()触发下一个中间件
- 注意:koa中间件不涉及路由功能,故不涉及method和path的判断!注意区分koa路由和koa中间件
- 官网的“级联”中有一个中间件示例
- 洋葱圈模型:中间件之间通过next函数联系,当一个中间件调用 next() 后,会将控制权交给下一个中间件, 直到下一个中间件不再执行 next() 后, 将会沿路折返,将控制权依次交换给前一个中间件。
中间件示例
- 新建koa2-test文件夹,
npm init -y
初始化环境 - 将package.js中的main改成app.js,新建app.js,将官网示例拷入:
- 该示例中有3个中间件:
- logger记录日志
- x-response-time记录请求时间
- response返回
- 安装koa框架:
npm i koa --save --registry=https://registry.npm.taobao.org
- 运行
node app.js
,访问8000端口:再访问http://localhost:8000/aaa和http://localhost:8000/bbb - 控制台可看到:访问8000端口耗时5ms,后面因为不需要加载东西,所以aaa和bbb都是0ms
- 代码执行过程:
- 运行项目时首先进入app.js
- app.js中注册了3个中间件
- 首先进入logger中间件,但马上就由next进入x-response-time中间件
- 在x-response-time中记录了当前时间,又由next进入response中间件
- 在response中间件返回Hello World显示在页面上
- 此时又返回继续执行response中间件,计算出时间差,并将时间差设置到ctx中
- 执行完后相当于第6行代码执行完,即又返回logger中间件中执行7、8行代码,从ctx中获取刚才设置的时间差,并最终打印出来
洋葱圈模型
- 上面示例的代码运行方式就是洋葱圈模型:各个中间件之间看似分离,实则是包裹的关系,第一个中间件包含了第二个中间件,第二个又包含了第三个
- 从代码来看:
- 比如,给每个中间件加上开始于结束:
- 结果: