TypeScript 和 Koa 2:async/await 全局错误处理程序问题
TypeScript and Koa 2: async/await issue with Global Error Handler
我正在使用 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
块 运行s.
但是,如果我在路由中抛出错误(无论我使用 throw
还是 ctx.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;
}
}));
问题有两个方面:
- 我的应用程序是否因为转译而无法捕获抛出的错误?我的意思是,如果转译的 JavaScript 会使用
async
和 await
关键字,而不是使用 yield
将其转译到生成器,它会起作用吗?
- 如果以上是正确的:有什么方法可以用 TypeScript 编写 Koa 2 应用程序现在?
编辑
我找到了一个“解决方案”来抛出我的错误,但我仍然不明白为什么 Koa 没有捕捉到它们。
此 for of
循环迭代我动态加载的控制器数组。对于每个控制器,我将 class (action.target) 的相应方法 (action.method) 使用指定的 Http 动词 (action.type).
但是,我还将上下文绑定到方法,以确保按照 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]);
}
是的,看起来这是纯粹的用户错误,没有确保每个中间件 returns 一个承诺(或者是一个异步函数)。
下面的async
是全部遗漏的:
for (let action of actionMetadata) {
router[action.type.toLowerCase()](action.route, async (ctx, next) => {
(new action.target)[action.method].bind(ctx)(ctx, next);
});
}
我正在使用 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
块 运行s.
但是,如果我在路由中抛出错误(无论我使用 throw
还是 ctx.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;
}
}));
问题有两个方面:
- 我的应用程序是否因为转译而无法捕获抛出的错误?我的意思是,如果转译的 JavaScript 会使用
async
和await
关键字,而不是使用yield
将其转译到生成器,它会起作用吗? - 如果以上是正确的:有什么方法可以用 TypeScript 编写 Koa 2 应用程序现在?
编辑
我找到了一个“解决方案”来抛出我的错误,但我仍然不明白为什么 Koa 没有捕捉到它们。
此 for of
循环迭代我动态加载的控制器数组。对于每个控制器,我将 class (action.target) 的相应方法 (action.method) 使用指定的 Http 动词 (action.type).
但是,我还将上下文绑定到方法,以确保按照 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]);
}
是的,看起来这是纯粹的用户错误,没有确保每个中间件 returns 一个承诺(或者是一个异步函数)。
下面的async
是全部遗漏的:
for (let action of actionMetadata) {
router[action.type.toLowerCase()](action.route, async (ctx, next) => {
(new action.target)[action.method].bind(ctx)(ctx, next);
});
}