内容简介:Koa是基于Nodejs的一个后端框架,算是比较常用的,核心思想就是中间件,Koa实现底层逻辑,其余的就需要自己实现,包括:session、数据库操作、文件上传、路由、模板、静态资源访问等一直以来都是使用这里并不打算写新手教程,可自行百度,只是写使用过程中遇到的一些疑惑
Koa是基于Nodejs的一个后端框架,算是比较常用的,核心思想就是中间件,Koa实现底层逻辑,其余的就需要自己实现,包括:session、数据库操作、文件上传、路由、模板、静态资源访问等
前言
一直以来都是使用 thinkjs
这个框架,集成很多功能,基本上就只需要负责写逻辑就OK了,所以想尝试一下Koa这种需要动手逐个实现功能的,类似也有express
这里并不打算写新手教程,可自行百度,只是写使用过程中遇到的一些疑惑
下面代码基于ES6、7
1、安装
官网推荐使用Nodejs >= 7.6的版本,小于这个版本需要采用babel方式曲线救国
实际使用发现,用了babel方式,可以解决koa本身的兼容问题,但koa的部分插件还是有问题,所以还是别采用这种方式了
2、配置文件
很多时候,我们需要有本地配置、测试配置、正式配置,如果每次发布都要注释掉其它两个环境的配置,就很容易出错
可以结合 package.json
中配置脚本命令,启动时候带不同参数来区分
"scripts": { "start": "set NODE_ENV=test && node ./app.js", "dev": "set NODE_ENV=dev && node ./app.js", "release": "set NODE_ENV=release && node ./app.js" }
思路为设置环境变量 NODE_ENV
的值,然后启动项目,上面对应的命令为: npm run (scripts的key)
然后在代码中根据环境变量的值,引用对应的配置文件
//根据不同的NODE_ENV,输出不同的配置对象 const env = process.env.NODE_ENV.replace(/\s+/,""); let config = require('./'+(env||"test"));
3、登陆态(上)
Koa本身是没有实现session这块,需要用插件才能实现
可以使用插件 koa-session2
,默认使用它,会将session内容保存在内存中,这样会有一个坏处,开发的时候需要经常重启服务,内存就被清空,意味着你需要重新登陆一次,所以一般不会存在内存中
- 本地与测试环境:采用文件形式保存
- 正式环境:采用数据库或者缓存方式保存,考虑到多台机器部署
而 koa-session2
并没有提供上述的保存方式,只提供了参数可选,具体方式需要自行实现,虽然也有对应的插件,不过使用时候发现并不好使,还是自己实现,其实很简单,覆盖三个函数即可:
//插件提供的基类 const { Store } = require("koa-session2"); //自定义一个类继承它 class FileStore extends Store { //构造函数,照抄即可 constructor() { super(); } //读取session内容的方法,sid为每个session的key,一串加密串,读取出session内容,返回 async get(sid, ctx) {} //设置session内容的方法,需要将session对象的内容保存起来 async set(session, { sid = this.getID(24)} = {}, ctx) { } //session过期或者删除时候,需要如何清除 async destroy(sid, ctx) {} }
实现完之后,需要配置session的保存参数 store
为上面实现的 new FileStore()
,这样就可以在所有的 controller
中读取和设置属性 ctx.session
了
4、登陆态(下)
登陆态一般会在登陆成功后、注册完进行设置,那如何判断是否登陆了?然后没有登陆跳转到登陆页面;最简单就是在每个controller的action中判断 ctx.session是否为空,但每个都写,很头疼
常见的方式是:自定义一个中间件,这样用户的每一个请求都会经过它,由它去判断
let loginMiddle = async (ctx, next) => { //获取用户请求的URL let url = ctx.request.url; //login路径为不需要登陆态,因为它是登陆方法,执行next则跳到controller中 if(url.indexOf("/login") > -1)return await next(); //假设登陆态是设置了user属性 let user = ctx.session.user; //没有登陆态 if(!user){ //跳转到登陆页 return ctx.response.redirect('/login'); } //正常执行controller await next(); };
只需要使用koa的时候,加载这个中间件就可以,需要注意:加载顺序需要在路由之前
登陆态是在用户浏览器设置一个加密的sessionid的cookie,而页面的地址与后台地址不同域名的话,则会出现种植失败,需要添加跨域允许种cookie才行,使用插件 koa-cors
,使用时候,设置参数 credentials : true
即可
5、防止CSRF漏洞
CSRF算是比较普遍的漏洞了,koa也有插件可以实现,不过使用起来不那么方便,直接将token种在页面中,对于后台只实现接口,没有页面渲染的不友好,所以可以自行实现个简单版的
在登录成功的action中,设置一个用于校验的token的cookie
//定义用户的token值,这里简单用时间戳,应该是用加密的md5值 let token = new Date() - 0; //将token设置到session中,用于未来校验 ctx.session._csrf = token; //将token种在用户的cookie中 ctx.cookies.set( '_csrf',token,{ path:'/', httpOnly:false, // 是否只用于http请求中获取 overwrite:true // 是否允许重写 } );
可以在上面的第四步中的登陆态中间件加入校验,这样就不需要每个action都去校验一次
let loginMiddle = async (ctx, next) => { //此处省略判断session登陆态 //... //获取请求中的token let csrfToken = ctx.request.method.toLowerCase() == "get" ? ctx.request.query["_csrf"] : ctx.request.body["_csrf"]; //没有传,提示token错误 if(!csrfToken)return ctx.body = "token错误"; //与session中的token对比 if(csrfToken != ctx.session._csrf) return ctx.body = "token错误"; //正常执行controller await next(); };
6、jsonp
koa有很多jsonp的插件,大部分是直接全局替换,即返回的内容直接就是jsonp方式,连普通的返回都没了
使用 koa-response-jsonp
插件,可以按需要自行使用jsonp方式,在controller的action中,使用 ctx.jsonp(object)
,请求参数固定为 callback=xxx
PS:当然你可以自行实现这个中间件,需要校验参数中的一些合法字符即可
7、数据校验
很多时候后台需要校验前端传送过来的数据,校验是否合法,可以避免后续操作很多问题,写在action中的话,会显得有些长,而action中更应该专注于逻辑
数据校验可以使用 parameter
插件,内置了基本的规则,比如:数字、字符串、邮箱等
//demo,简单的三条规则 mobile : {type : 'id',required:false} email : {type : 'email',required:false} nickname : {type : 'string',required: true,min:1}
校验可以写在 router
路由中,比如下面这个,在调用具体action前,先校验数据
router.get('/get_order', async (ctx)=>{ //校验规则 let rule = { openid : {type : 'string',required: false,min:6,allowEmpty:true}, code : {type : 'string',required:true,min:6} }; //校验数据 let ret = validateUtil.validate(rule,ctx.request.query); //校验失败,返回错误信息,不执行具体action if(ret.status == false)return ctx.body = ret; //校验完毕,执行后续操作 await controller.get_order(ctx); });
8、设置404
很奇怪,koa是连这个也没有,需要自己去实现,不麻烦,就是所有的路由规则都没有命中,就是404了
//设定404页面,即所有路由都没命中 router.get('*', async (ctx, next) => { ctx.status = 404; await ctx.render('error/404'); });
9、日志
一般都用Log4js来做日志记录操作,本地开发的时候还好好的,直到用上了pm2来启动,以及采用了多线程方式,日志就哑火了,一个都没记录了
Log4js的配置,需要加上这个:
- "pm2": true
- "pm2InstanceVar": 'INSTANCE_ID'
以及需要再pm2.json文件加上:
- "instances": 0
- "instance_var": "INSTANCE_ID"
10、其余常用的插件
- koa-bodyparser:主要用于获取post请求的参数
- koa-helmet:安全插件,防止 SQL 注入与攻击等
- koa-router:路由插件
- koa-static:静态资源处理,用户显示css、img、js等
- koa-views:模板渲染,需要搭配ejs插件使用
- axios:请求第三方接口的插件
后话
Koa很多事情都需要自行去处理解决,虽然有插件能帮忙完成,但根据自身需要,还是需要手动去实现一些功能,总体来说,起步上手,会比什么都搭好的thinkjs要麻烦,但也是因为这样,可以只保留自己业务需要的功能,其余不需要就可以放弃掉,性能上会有所提升。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。