详解KOA2如何手写中间件(装饰器模式)

2020-06-17 06:53:22易采站长站整理

文件: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();
};
};

在上面代码中由几点是需要我们注意的,即 next 的调用以及为什么通过流接收数据、处理数据和将数据挂在 ctx.request.body 要在 Promise 中进行。

首先是 next 的调用,我们知道 Koa 的 next 执行,其实就是在执行下一个中间件的函数,即下一个 use 中的 async 函数,为了保证后面的异步代码执行完毕后再继续执行当前的代码,所以我们需要使用 await 进行等待,其次就是数据从接收到挂在 ctx.request.body 都在 Promise 中执行,是因为在接收数据的操作是异步的,整个处理数据的过程需要等待异步完成后,再把数据挂在 ctx.request.body 上,可以保证我们在下一个 use 的 async 函数中可以在 ctx.request.body 上拿到数据,所以我们使用 await 等待一个 Promise 成功后再执行 next 。

koa-better-body 中间件模拟

koa-bodyparser 在处理表单提交时还是显得有一点弱,因为不支持文件上传,而 koa-better-body 则弥补了这个不足,但是 koa-better-body 为 Koa 1.x 版本的中间件, Koa 1.x 的中间件都是使用 Generator 函数实现的,我们需要使用 koa-convert 将 koa-better-body 转化成 Koa 2.x 的中间件。


npm install koa koa-better-body koa-convert path uuid

koa-better-body 具体用法如下:

koa-better-body 的用法


const Koa = require("koa");
const betterBody = require("koa-better-body");
const convert = require("koa-convert"); // 将 koa 1.0 中间转化成 koa 2.0 中间件