TypeScript и Koa 2: Проблема async / await с глобальным обработчиком ошибок


Я пишу приложение с 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), все, что я получаю, - это сообщение об ошибке по умолчанию "не найдено" - так что любые ошибки, которые я бросаю, никогда не будут пойманы, и, следовательно, мой обработчик ошибок не будет обрабатывать его.

Теперь рассмотрим следующий транспилированный 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 будет использовать async и await ключевые слова, а не транспонировать его в генераторы с использованием yield?
  2. Если вышеизложенное верно: есть ли способ написать приложения Koa 2 с помощью TypeScript теперь ?

Edit

Я нашел "решение", чтобы заставить мои ошибки бросать, но я все еще не понимаю, почему Коа не поймал их.

Этот цикл for of повторяет массив контроллеров, которые я динамически загружаю. Для каждого контроллера я прилагаю соответствующий метод (действие.метод) класса (действие.цель) к маршруту (действие.маршрут) с использованием указанного http глагола (action.тип).

Однако я также связываю контекст с методом, чтобы гарантировать, что, согласно конвенциям 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 2

1 ответ:

Верно, похоже, что это была чистая ошибка пользователя, не гарантирующая, что каждое промежуточное ПО возвращает обещание (или является асинхронной функцией).

async в следующем-это все, чего не хватало:

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