Node.js 有时会给出 UnhandledPromiseRejection,而我的 catch 被忽略了

问题描述 投票:0回答:1

所以我的代码是这样的:

router.get('/myapi/someotherapi/:id', (request, response) => {
    console.log('api: GET /admin/myapi/someotherapi/:id');
    console.log('Reject star redeem requests by id');
    auth.verifyToken(request, response, { role: 'Admin' }).then(b_tokenValidated => {
        if (b_tokenValidated && b_tokenValidated.statusCode !== 401) {
            const myId = b_tokenValidated.userId;
            const updateLastActive = user.updateLastActive(myId, request);
            const mySpecialFunction = myLib.mySpecialFunction(
                request.params.id, myId
            );
            updateLastActive.then(() => {
                mySpecialFunction.then(r => {
                    generalApiResponseSender(response, r);
                })
                .catch((err) => {
                    console.log('mySpecialFunction failed: ', err);
                    generalApiErrorHandler(response, err);
                })
            })
            .catch((err) => {
                generalApiErrorHandler(response, err);
            })
        }
        else {
            generalApiErrorHandler(
                response,
                {
                    status: 401,
                    message: "You haven't logged in or token has expired."
                }
            )
        }
    }).catch((err) => {
        console.log('verifyToken failed: ', err);
        let errCode = 401;
        let errMsg = "You haven't logged in or token has expired.";
        if (typeof err === 'number') {
            errCode = err;
            errMsg = "Please see error code for more details.";
        }
        generalApiErrorHandler(
            response,
            {
                status: errCode,
                message: errMsg
            }
        )
    })
})

export const generalApiErrorHandler = (response, err) => {
    if (!response.headersSent) {
        if (err['status'] && err['message']) {
            response.status(err['status']).send(err['message']);
        }
        else if (typeof err === 'number') {
            response.sendStatus(err);
        }
        else {
            response.sendStatus(500);
        }
    }
}

export const generalApiResponseSender = (response, data) => {
    if (!response.headersSent) {
        if (typeof data !== "number") {
            response.send(snake2Camel(data));
        }
        else {
            response.sendStatus(data);
        }
    }
}

我收到这样的错误:

api: GET /myapi/someotherapi/:id
My function is triggered
id:  30
myId:  1
Request not found, abort.
update_query failed, error:  404
mySpecialFunction failed:  404
api: GET /myapi/someotherapi/:id
My function is triggered
id:  30
myId:  1
Request not found, abort.
update_query failed, error:  404
node:internal/process/promises:246
          triggerUncaughtException(err, true /* fromPromise */);
          ^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "404".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

可以看到,这两个调用是完全一样的

第一次调用正常触发错误处理程序,并将错误代码发送回前端。

然而,第二次调用声明没有错误处理程序来处理它,因此它选择停止整个应用程序。

任何人都可以向我解释为什么会发生这种情况,我该如何预防?第二次没有被catch函数捕捉到的错误可能是什么原因?

我想使用 return 而不是 throw 可能会解决这个问题,因为我定义了 404 错误。但我不认为最好的做法是返回错误代码,就像它不是错误而是有效的返回值一样。

附言。我发现有人说

async
不会与 catch 一起工作(UnhandledPromiseRejection 尽管捕捉到了期望),所以我从函数中删除了所有
async
await
。然而,这仍然发生。

更新(22/4/2023):

感谢@Konrad,应用程序现在不会自行停止。我得到的新日志如下:

api: GET /myapi/someotherapi/:id
My function is triggered
id:  30
myId:  1
Nothing is updated, abort.
update_query failed, error:  404
Unhandled Rejection at: Promise Promise { <rejected> 404 } reason: 404
(node:21136) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 5)

此外,前端仍然按预期收到 404 状态,这意味着错误一定是正确抛出的,只是 Node.js 未能发现。

javascript node.js express error-handling try-catch
1个回答
0
投票

您的问题是

updateLastActive
mySpecialFunction
都是您同时创建的承诺,并且两者都可能拒绝 - 但您只处理其中一个错误。

你应该写任一个

const myId = b_tokenValidated.userId;
Promise.all([
    user.updateLastActive(myId, request),
    myLib.mySpecialFunction(request.params.id, myId),
]).then(([_, result]) => {
    generalApiResponseSender(response, result);
}, (err) => {
    generalApiErrorHandler(response, err);
});

const myId = b_tokenValidated.userId;
user.updateLastActive(myId, request).then(() => {
    myLib.mySpecialFunction(request.params.id, myId).then((result) => {
        generalApiResponseSender(response, result);
    })
    .catch((err) => {
        console.log('mySpecialFunction failed: ', err);
        generalApiErrorHandler(response, err);
    })
})
.catch((err) => {
    generalApiErrorHandler(response, err);
})

const myId = b_tokenValidated.userId;
user.updateLastActive(myId, request).then(() => {
    return myLib.mySpecialFunction(request.params.id, myId).catch(err => {
        console.log('mySpecialFunction failed: ', err);
        throw err;
    });
}).then(result => {
    generalApiResponseSender(response, result);
}, err => {
    generalApiErrorHandler(response, err);
});
© www.soinside.com 2019 - 2024. All rights reserved.