GX博客

分享个人 Full-Stack JavaScript 项目开发经验

Koa2的中间件应用例子

Koa2 的 Context 将 node.js 的 request 和 response 对象封装到单个 ctx 对象中。这个 ctx 对象会在中间件管道中传递。Koa2 丢弃了回调函数,取而代之的是 async 函数。它使异步代码看起来更“像”同步,而且利于捕获和处理错误。中间件中调用 await next() 即可将控制传递给定义的下一个中间件。


异步函数表达式

async function 关键字用来在表达式中定义异步函数,它也可以使用匿名箭头函数的形式。

async (param) => {
    [return_value] = await expression;
}

在异步函数表达式中,await 操作符用于等待一个 Promise 对象。await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。如果 Promise 正常处理,其回调的 resolve 函数参数将作为 await 表达式的值,然后继续执行 async function。如果 Promise 处理异常,await 表达式会把回调的 reject 函数参数作为异常抛出。

如果 expression 不是一个 Promise,await 会把它转换为已正常处理的 Promise,然后等待其处理结果。


app 级别的中间件

设置内容安全策略 nonce 的 app 级别中间件例子:

const Koa = require("koa");
const app = new Koa();
const onerror = require("koa-onerror");
const uuid = require("node-uuid");

// 错误处理
onerror(app, {
    template: './views/error/50x.html'
});

// 同步中间件,无需使用 async 函数
app.use( (ctx, next) => {
    // ctx.state 为 Koa2 推荐的命名空间,用于通过中间件传递信息和传递前端视图数据。
    ctx.res.state = {};
    // 生成一个 v4 UUID (随机的通用唯一识别码)
    ctx.res.state.nonce = ctx.state.nonce = uuid.v4();
    return next();
});

// 创建数据库实例于 app 上下文中
app.context.mysql = require("./lib/mysql");

其中的 app.context 是 ctx 的原型,我们可以通过编辑 app.context 为 ctx 添加其它属性。


router 级别的中间件

获取网站基础信息的 router 级别中间件例子:

const router = require('koa-router')();
const controllers = require('../controllers');
const websiteMessage = require("../lib/middleware/websiteMessage");

router.get('/', websiteMessage, controllers.front.home.index);

websiteMessage.js

module.exports = async (ctx, next) => {
    // ctx.mysql
    // ......
    ctx.state.websiteMessage = websiteMessage_data;
    await next();
};

要了解更多 koa-router 的用法,请点击这里

中间件的错误捕获

在中间件中,我们需要对可能发生错误的地方进行错误捕获,否则 koa-onerror 中间件会在 app.context.onerror 中响应 500(Internal Server Error)并投递相关 html。

module.exports = async (ctx, next) => {
    // ......
    try {
        throw new Error('??');
    } catch (e) {
        console.error(e);
    }
    // ......
    await next();
}

版权声明:

本文为博主原创文章,若需转载,须注明出处,添加原文链接。

https://leeguangxing.cn/blog_post_36.html