TypeScript和Koa 2:异步/等待全局错误处理程序的问题

时间:2016-08-21 19:20:00

标签: typescript error-handling async-await koa ecmascript-7

我正在使用TypeScript和Koa 2编写应用程序。

但是,我遇到的问题是我的全局Koa错误处理程序没有捕获我的应用程序中抛出的错误。

以下面的中间件为例(这是加载任何路由之前的第一个中间件):

app.use(async(ctx, next) => {
    console.log("ErrorHandler loaded...");
    try {
        console.log("Trying for error...");
        await next();
    } catch (err) {
        console.log("Caught error...");
        ctx.status = err.status || 500;
        ctx.response.body = "Error: " + err.message;
    }
});

访问我的路由时,我可以看到加载了错误处理程序并且try块运行。

但是,如果我在路由中抛出错误(无论我使用throw还是ctx.throw),我得到的都是默认错误消息“Not found” - 所以,任何错误我throw永远不会被捕获,因此,我的错误处理程序将不会处理它。

现在考虑以下转换的JavaScript:

app.use((ctx, next) => __awaiter(this, void 0, void 0, function* () {
    console.log("ErrorHandler loaded...");
    try {
        console.log("Trying for error...");
        yield next();
    }
    catch (err) {
        console.log("Caught error...");
        ctx.status = err.status || 500;
        ctx.response.body = "Error: " + err.message;
    }
}));

问题是双重的:

  1. 我的应用程序是否因为转换而无法捕获抛出的错误?我的意思是,如果转换后的JavaScript会使用asyncawait关键字,而不是使用yield将其转换为生成器吗?
  2. 如果以上是正确的:有没有办法用TypeScript 现在编写Koa 2应用程序?
  3. 修改

    我找到了一个“解决方案”来解决我的错误,但我仍然不明白为什么Koa没有抓住它们。

    这个for of循环迭代我动态加载的控制器数组。对于每个控制器,我使用指定的Http动词(action.type)将类(action.target)的相应方法(action.method)附加到路由(action.route)。

    但是,我也将上下文绑定到方法,以确保根据Koa的约定,this绑定到Context

    for (let action of actionMetadata) {
        router[action.type.toLowerCase()](action.route, (ctx, next) => {
            (new action.target)[action.method].bind(ctx)(ctx, next);
        });
    }
    

    以上原因导致未捕获错误的问题。

    相比之下,以下代码有效:Koa现在捕获了错误。但这意味着this现在不再是Context

    我可以忍受,因为Context是我的路由中的第一个参数,但我不明白为什么错误没有像错误处理程序(这是我的第一个中间件)之后的所有中间件一样被捕获应该在try区块内运行:

    for (let action of actionMetadata) {
        router[action.type.toLowerCase()](action.route, (new action.target )[action.method]);
    }
    

1 个答案:

答案 0 :(得分:1)

是的,看起来这是纯粹的用户错误,因为没有确保每个中间件都返回一个promise(或者是一个异步函数)。

以下async是所有缺失的:

for (let action of actionMetadata) {
    router[action.type.toLowerCase()](action.route, async (ctx, next) => {
        (new action.target)[action.method].bind(ctx)(ctx, next);
    });
}