koa2的中间件功能及应用示例


Posted in Javascript onMarch 05, 2020

最近因为开发一个自己的博客网站,学习了koa2的搭建,写了一些自己认为比较重要或需要知道的koa2中间件作用和使用场景。

koa-router

路由中间件

下载

npm i koa-router

使用

普通使用方法

需要注意的是引入的koa-router是一个方法,引入后需要执行这个方法。

const Koa = require('koa'); 
const app = new Koa(); 
const router = require('koa-router')(); 

// 配置路由url 
// 默认url 
router.get('/', async (ctx, next) => { 
 ctx.body = 'Hello World'; 
}); 

// 自定义url 
router.get('/hello/:name', async (ctx, next) => { 
 var name = ctx.params.name; 
 ctx.response.body = \`<h1>Hello, ${name}!</h1>\`; 
}); 

// 注册路由 
app.use(router.routes(), router.allowedMethods());

也可以按需引入并注册路由,可注册多个路由。

不同请求下接收的参数获取

router.get

通过ctx.query获取参数

router.post
通过ctx.request.body获取参数

动态路由 router.get('/:id', func)
通过ctx.params获取参数

遍历注册router

首先引入nodejs中的fs模块,使用fs的readdirSync方法获取到指定目录的所有文件名,遍历引入路由模块并注册。

const fs = require('fs'); 

// fs.readdirSync 获取指定目录下的所有文件名称,遍历引入路由模块并注册 
fs.readdirSync('./routes').forEach(route=> { 
 let api = require(\`./routes/${route}\`); 
 app.use(api.routes(), api.allowedMethods()); 
});

koa-router中的其它api

router.prefix(prefix) 添加url前缀

设置已经初始化的路由器实例的路径前缀

router.prefix('/user'); 
router.post('/login', function(ctx, next) { 
 ... 
}); 

// 实际路径 /user/login

router.use(url|[url1,url2,...], (ctx, next) => {...}) 路由中间件

使用场景:我们通常需要通过验证用户和用户权限来判定用户是否能使用该接口,如果在每个接口都写一次验证非常麻烦且不好维护。这时我们就需要路由中间件先进行验证,再执行下面操作。

router.use的第一个参数为一个路径或者由多个需要使用中间件的路径组成的数组(需要注意的是,如果路由设置了url前缀,需要在设置前缀后注册中间件,参数中的url不需要设置前缀)。

router.use的第二个参数为函数,函数传递ctx和next两个参数,可通过ctx进行权限验证后,判断是否执行next调用接口。这里特别需要注意的是函数使用next的时候需要添加await,如果不添加,在调用接口前,接口就会返回结果,前台则无法获取到数据。

// this is wrong 
 app.use(function (ctx, next) { 
  ctx.set("Access-Control-Allow-Origin", "\*"); 
  next(); 
 }); 
 // this is right 
 app.use(async function (ctx, next) { 
  ctx.set("Access-Control-Allow-Origin", "\*"); 
  await next(); 
 });

koa-bodyparser处理post请求

处理post请求时,我们会遇到一个问题,无论是node的request对象还是koa的request对象,都没办法解析request的body,我们就需要下载并引入一个解析body的中间件koa-bodyparser,koa-bodyparser的具体配置详见下面的说明,这里我们直接放入使用方式。

// 引入路由文件 
 const index = require('./routes/index.js'); 
 const user = require('./routes/user.js'); 

 // 引入解析request.body的中间件 
 const bodyparser = require('koa-bodyparser'); 

 // 注册bodyparser,需要注意,bodyparser的注册一定要在router路由注册之前 
 app.use(bodyparser({ 
  enableTypes:\['json', 'form', 'text'\] 
 })); 

 ... 

 // 注册routes 
 app.use(index.routes(), index.allowedMethods()); 
 app.use(user.routes(), user.allowedMethods());

koa-bodyparser

如上所述,koa-bodyparser用于解析request.body,因为node和koa的request无法解析body。

下载

npm i koa-bodyparser

使用

const bodyparser = require('koa-bodyparser');

在注册运行时,bodyparser方法中可传入对象,作相应配置。

- enableTypes:解析器只在配置了enableTypes时解析请求类型,默认是['json', 'form']。
- encoding:请求编码,默认是utf-8。
- formLimit:urlencoded body的imit如果主体最终大于此限制,则返回一个413错误代码。默认是56 kb。
- jsonLimit:json主体的限制。默认是1 mb。
- textLimit:文本主体的限制。默认是1 mb。
- strict:当设置为true时,JSON解析器将只接受数组和对象。默认是正确的。参见正文中的严格模式。在严格模式下,ctx.request。body总是一个对象(或数组),这避免了很多类型判断。但文本正文总是返回字符串类型。
- detectJSON:自定义json请求检测函数。默认为null。

app.use(bodyparser({ 
 detectJSON: function (ctx) { 
 return /\\.json$/i.test(ctx.path); 
 } 
}));

- extendTypes:支持扩展类型

app.use(bodyparser({ 
   extendTypes: { 
   json: \['application/x-javascript'\] // 解析application/x-javascript 类型 作为JSON字符串 
   } 
  }));

- onerror:支持自定义错误句柄,如果koa-bodyparser抛出一个错误,您可以自定义响应如下:

app.use(bodyparser({ 
   onerror: function (err, ctx) { 
   ctx.throw('body parse error', 422); 
   } 
  }));

- disableBodyParser:可以通过设置ctx动态禁用body解析器。disableBodyParser = true。

app.use(async (ctx, next) => { 
   if (ctx.path === '/disable')     ctx.disableBodyParser = true; 
   await next(); 
  }); 
  app.use(bodyparser());

koa-logger

请求响应监听日志

下载

npm i koa-logger

使用

~~// 引入日志中间件 
const logger = require('koa-logger'); 

// 注册日志中间件 
app.use(logger()); ~~

koa-session

用于Koa的简单会话中间件。默认为基于cookie的会话,并支持外部存储。

session

我们知道,http协议是无状态的,当用户进行登录后,并不会保存账户密码,如果我们需要维持用户的登录状态,就需要使用一些方法。目前主流的用户认证方法有基于token和基于session两种方式。

基于token的认证可以使用koa-jwt中间件,基于session的认证则使用标题的koa-session。

下载

npm i koa-session

使用

app.js 入口文件中注册session

const CONFIG = { 
 key: 'koa:sess', /\*\* (string) cookie key (default is koa:sess) \*/ 
 /\*\* (number || 'session') maxAge in ms (default is 1 days) \*/ 
  // 状态保存最大时间,默认为一天 
 maxAge: 86400000, 
 autoCommit: true, /\*\* (boolean) 自动保存头部 (default true) \*/ 
 overwrite: true, /\*\* (boolean) 能否覆盖 (default true) \*/ 
 httpOnly: true, /\*\* (boolean) httpOnly or not (default true) \*/ 
 signed: true, /\*\* (boolean) signed or not (default true) \*/ 
 /\*\* (boolean) 强制在每个响应上设置会话标识符cookie。过期将重置为原始maxAge,重新设置过期倒计时。 (default is false) \*/ 
 rolling: false, 
 /\*\* (boolean) 当会话快过期时续订会话,这样我们可以始终保持用户登录。(default is false)\*/ 
 renew: false, 
}; 

// 如果你所有都为默认配置,则不需要传递配置参数,app.use(session(app))即可 
app.use(session(sessionConfig, app));

session的使用

注册后可以通过上下文ctx找到session属性,下面代码将用户信息存入session属性中,并创建key和value

user.js

// 用户登录 
static async login(ctx, next) {

const data = ctx.request.body 
const schema = Joi.object().keys({ 
 username: Joi.string().required(), 
 password: Joi.string().required(), 
}) 
let result = Joi.validate(data, schema) 
// 如果有字段类型错误 
if(result.error) { 
 return ctx.response.body = { status: 400, msg: result.error.details}; 
} 
let { username, password } = result.value // 验证过后的数据 
// 查找是否有该用户 
const userInfo = await usersModel.findByName(username) 
// 如果有该用户,继续验证密码是否正确 
if (userInfo) { 
 const userInfo2 = await usersModel.findOne({ username, password }) 
 if (userInfo2) { 
  ctx.response.body = {state: 200, msg: '登录成功'} 
  // 设置session 
  ctx.session.userInfo = userInfo2 
 } else { 
  ctx.response.body = {state: 410, msg: '密码错误'} 
 } 
// 如果没有该用户,返回结果 
} else { 
 ctx.response.body = {state: 410, msg: '该用户不存在'} 
} 
return ctx.response.body 
}

koa-router路由中间件中验证session,这里需要注意的是next()方法前一定要使用await,不然程序不会等待next()方法执行。

export const verifyUser = async (ctx, next) => {

if (ctx.session.userInfo) { 
 await next() 
} else { 
 return ctx.response.body = { state: 401, msg: '无权限访问' } 
} 
}

koa2-cors

用于解决跨域问题

下载

npm install koa2-cors

使用

app.use(cors())

到此这篇关于koa2的中间件功能及应用示例的文章就介绍到这了,更多相关koa2 中间件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
5 cool javascript apps
Mar 24 Javascript
基于jQuery的ajax功能实现web service的json转化
Aug 29 Javascript
Javascript 键盘事件的组合使用实现代码
May 04 Javascript
jQuery的Ajax用户认证和注册技术实例教程(附demo源码)
Dec 08 Javascript
JavaScript必知必会(六) delete in instanceof
Jun 08 Javascript
jQuery自定义数值抽奖活动代码
Jun 11 Javascript
jQuery轻松实现无缝轮播效果
Mar 22 jQuery
Angular 4根据组件名称动态创建出组件的方法教程
Nov 01 Javascript
详解使用 Node.js 开发简单的脚手架工具
Jun 08 Javascript
JavaScript 预解析的4种实现方法解析
Sep 03 Javascript
layui table复选框禁止某几条勾选的实例
Sep 20 Javascript
vue-socket.io跨域问题有效解决方法
Feb 11 Javascript
微信小程序利用for循环解决内容变更问题
Mar 05 #Javascript
javascript将16进制的字符串转换为10进制整数hex
Mar 05 #Javascript
js将URL网址转为16进制加密与解密函数
Mar 04 #Javascript
基于node+websocket+html实现腾讯课堂聊天室聊天功能
Mar 04 #Javascript
VUE实现Studio管理后台之鼠标拖放改变窗口大小
Mar 04 #Javascript
微信小程序如何加载数据库真实数据的实现
Mar 04 #Javascript
微信小程序开发搜索功能实现(前端+后端+数据库)
Mar 04 #Javascript
You might like
php下通过IP获取地理位置的代码(小偷程序)
2011/06/09 PHP
PHP将整个网站生成HTML纯静态网页的方法总结
2012/02/05 PHP
php实现通过soap调用.Net的WebService asmx文件
2017/02/27 PHP
关于PHP通用返回值设置方法
2017/03/31 PHP
TP5框架实现上传多张图片的方法分析
2020/03/29 PHP
jquery随意添加移除html的实现代码
2011/06/21 Javascript
JavaScript的Module模式编程深入分析
2013/08/13 Javascript
jquery 隐藏与显示tr标签示例代码
2014/06/06 Javascript
jQuery超简单选项卡完整实例
2015/09/26 Javascript
JavaScript实现点击按钮切换网页背景色的方法
2015/10/17 Javascript
PassWord输入框代码分享
2016/06/07 Javascript
js中创建对象的几种方式
2017/02/05 Javascript
使用jQuery监听扫码枪输入并禁止手动输入的实现方法(推荐)
2017/03/21 jQuery
Javascript实现信息滚动效果
2017/05/18 Javascript
Vue非父子组件通信详解
2017/06/12 Javascript
Bootstrap table中toolbar新增条件查询及refresh参数使用方法
2018/05/18 Javascript
利用jqgrid实现上移下移单元格功能
2018/11/07 Javascript
判断“命令按钮”是否被鼠标单击详解
2019/07/31 Javascript
微信提示 在浏览器打开 效果实现过程解析
2019/09/10 Javascript
聊聊Vue中provide/inject的应用详解
2019/11/10 Javascript
[04:13]2018国际邀请赛典藏宝瓶Ⅱ饰品一览
2018/07/21 DOTA
python脚本实现统计日志文件中的ip访问次数代码分享
2014/08/06 Python
Python3爬虫使用Fidder实现APP爬取示例
2018/11/27 Python
如何一键升级Python所有包
2020/11/05 Python
在终端启动Python时报错的解决方案
2020/11/20 Python
浅析python实现动态规划背包问题
2020/12/31 Python
Python调用系统命令os.system()和os.popen()的实现
2020/12/31 Python
python使用scapy模块实现ARP扫描的过程
2021/01/21 Python
HashMap和Hashtable的区别
2013/05/18 面试题
档案室主任岗位职责
2014/02/12 职场文书
《乌塔》教学反思
2014/02/17 职场文书
幼儿教师求职信
2014/05/24 职场文书
大学生第一学年自我鉴定
2014/09/12 职场文书
六一文艺汇演主持词
2015/06/30 职场文书
2016年员工年度考核评语
2015/12/02 职场文书
vue使用节流函数的踩坑实例指南
2021/05/20 Vue.js