Koa2 中间件原理解析 —— 看了就会写

本文深入解析Koa2中间件的洋葱模型,通过模拟实现koa-bodyparser、koa-better-body、koa-views、koa-static和koa-router等常见中间件,阐述中间件的工作原理及异步处理机制。通过学习,读者将了解如何开发自己的Koa2中间件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述


阅读原文


前言

Koa 2.x 版本是当下最流行的 NodeJS 框架,Koa 2.0 的源码特别精简,不像 Express 封装的功能那么多,所以大部分的功能都是由 Koa 开发团队(同 Express 是一家出品)和社区贡献者针对 Koa 对 NodeJS 的封装特性实现的中间件来提供的,用法非常简单,就是引入中间件,并调用 Koause 方法使用在对应的位置,这样就可以通过在内部操作 ctx 实现一些功能,我们接下来就讨论常用中间件的实现原理以及我们应该如何开发一个 Koa 中间件供自己和别人使用。


Koa 的洋葱模型介绍

我们本次不对洋葱模型的实现原理进行过多的刨析,主要根据 API 的使用方式及洋葱模型分析中间件是如何工作的。

// 洋葱模型特点
// 引入 Koa
const Koa = require("koa");

// 创建服务
const app = new Koa();

app.use(async (ctx, next) => {
   
    console.log(1);
    await next();
    console.log(2);
});

app.use(async (ctx, next) => {
   
    console.log(3);
    await next();
    console.log(4);
});

app.use(async (ctx, next) => {
   
    console.log(5);
    await next();
    console.log(6);
});

// 监听服务
app.listen(3000);

// 1
// 3
// 5
// 6
// 4
// 2

我们知道 Koause 方法是支持异步的,所以为了保证正常的按照洋葱模型的执行顺序执行代码,需要在调用 next 的时候让代码等待,等待异步结束后再继续向下执行,所以我们在 Koa 中都是建议使用 async/await 的,引入的中间件都是在 use 方法中调用,由此我们可以分析出每一个 Koa 的中间件都是返回一个 async 函数的。


koa-bodyparser 中间件模拟

想要分析 koa-bodyparser 的原理首先需要知道用法和作用,koa-bodyparser 中间件是将我们的 post 请求和表单提交的查询字符串转换成对象,并挂在 ctx.request.body 上,方便我们在其他中间件或接口处取值,使用前需提前安装。

npm install koa koa-bodyparser

koa-bodyparser 具体用法如下:

// koa-bodyparser 的用法
const Koa = require("koa");
const bodyParser = require("koa-bodyparser");

const app = new Koa();

// 使用中间件
app.use(bodyParser());

app.use(async (ctx, next) => {
   
    if (ctx.path === "/" && ctx.method === "POST") {
   
        // 使用中间件后 ctx.request.body 属性自动加上了 post 请求的数据
        console.log(ctx.request.body);
    }
});

app.listen(3000);

根据用法我们可以看出 koa-bodyparser 中间件引入的其实是一个函数,我们把它放在了 use 中执行,根据 Koa 的特点,我们推断出 koa-bodyparser 的函数执行后应该给我们返回了一个 async 函数,下面是我们模拟实现的代码。

// 文件: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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值