Open
Description
一、是什么
中间件(Middleware)是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的
在NodeJS
中,中间件主要是指封装http
请求细节处理的方法
例如在express
、koa
等web框架中,中间件的本质为一个回调函数,参数包含请求对象、响应对象和执行下一个中间件的函数
在这些中间件函数中,我们可以执行业务逻辑代码,修改请求和响应对象、返回响应数据等操作
express和koa区别:
- Express 为线型模型,而 Koa 则为洋葱型模型
- 集成度
- Express自带了
Router
和Static
的中间件 - Koa需要自行安装
Router
和Static
的中间件
- Express自带了
- 内部原理
- Express是基于回调,深层次的异常捕获不了
- Koa是使用的号称异步终极解决方案的
Async/Await
,也就是基于Promise
,使用Try-Catch
来捕获错误
- 内部语法
- Express基于
ES5
- Koa基于
ES7
- Express基于
二、封装
koa
是基于NodeJS
当前比较流行的web框架,本身支持的功能并不多,功能都可以通过中间件拓展实现。通过添加不同的中间件,实现不同的需求,从而构建一个Koa
应用
Koa
中间件采用的是洋葱圈模型,每次执行下一个中间件传入两个参数:
ctx
:封装了request 和 response 的变量next
:进入下一个要执行的中间件的函数
下面就针对koa进行中间件的封装:
Koa
的中间件就是函数,可以是async
函数,或是普通函数
// async 函数
app.use(async (ctx, next) => {
console.log("1")
await next();
console.log("1 end");
});
// 普通函数
app.use((ctx, next) => {
console.log("1")
return next().then(() => {
console.log("1 end");
});
});
中间件的执行过程
app.use(async (ctx, next) => {
console.log("1")
await next();
console.log("1 end");
});
app.use(async (ctx, next) => {
console.log("2")
await next();
console.log("2 end");
});
app.use(async (ctx, next) => {
console.log("3")
await next();
console.log("3 end");
});
执行结果如下
1
2
3
3 end
2 end
1 end
通过中间件封装常用的功能
token校验
module.exports = (options) => async (ctx, next) {
try {
// 获取 token
const token = ctx.header.authorization
if (token) {
try {
// verify 函数验证 token,并获取用户相关信息
await verify(token)
} catch (err) {
console.log(err)
}
}
// 进入下一个中间件
await next()
} catch (err) {
console.log(err)
}
}
日志模块
const fs = require('fs')
module.exports = (options) => async (ctx, next) => {
const startTime = Date.now()
const requestTime = new Date()
await next()
const ms = Date.now() - startTime;
let logout = `${ctx.request.ip} -- ${requestTime} -- ${ctx.method} -- ${ctx.url} -- ${ms}ms`;
// 输出日志文件
fs.appendFileSync('./log.txt', logout + '\n')
}
koa-bodyparser
koa-bodyparser
中间件是将我们的post
请求和表单提交的查询字符串转换成对象,并挂在ctx.request.body
上,方便我们在其他中间件或接口处取值
// 文件:my-koa-bodyparser.js
const querystring = require("querystring");
module.exports = function bodyParser() {
return async (ctx, next) => {
await new Promise((resolve, reject) => {
// 存储数据的数组
let dataArr = [];
// 接收数据
ctx.req.on("data", data => dataArr.push(data));
// 整合数据并使用 Promise 成功
ctx.req.on("end", () => {
// 获取请求数据的类型 json 或表单
let contentType = ctx.get("Content-Type");
// 获取数据 Buffer 格式
let data = Buffer.concat(dataArr).toString();
if (contentType === "application/x-www-form-urlencoded") {
// 如果是表单提交,则将查询字符串转换成对象赋值给 ctx.request.body
ctx.request.body = querystring.parse(data);
} else if (contentType === "applaction/json") {
// 如果是 json,则将字符串格式的对象转换成对象赋值给 ctx.request.body
ctx.request.body = JSON.parse(data);
}
// 执行成功的回调
resolve();
});
});
// 继续向下执行
await next();
};
};