如何解决Express应用Unhandled promise rejection并传递异常到错误中间件
问题原因
- 第一个问题:你原来的
getActiveId方法在末尾加了.catch(er => er),这个操作会把 rejected 状态的 Promise 转换成 resolved 状态,返回值就是捕获到的错误对象。所以你await api.getActiveId(id)永远不会抛出异常,只会把错误当正常结果返回,自然进不了路由的catch块。 - 第二个问题:你路由的
catch块里只返回了res.json({ success: false }),没有调用next(err),所以就算捕获到了错误,也不会触发全局错误处理中间件。 - 第三个问题:你模拟代码运行时报未处理Promise rejection,大概率是你路由代码里的
id变量没有定义(你没从请求参数里取值,直接用了id变量,触发了引用错误),这个错误发生在try块外,没有被捕获,同时Express默认不会自动处理async路由抛出的异常,就会报这个警告。
修复步骤
1. 修复getActiveId,不要吞错误
要么删掉末尾的catch,要么在catch里抛出错误,让外层能捕获到:
exports.getActiveId = id => axiosInstance .get('/example') .then(({ data }) => data) .catch(er => { // 不要直接return er,抛出错误才能让外层catch到 throw er // 也可以写成 return Promise.reject(er),效果一致 });
你写的模拟getActiveId逻辑本身是对的,没有问题,不用改。
2. 修复路由处理函数
首先补全id的取值逻辑,然后在catch块里调用next(err)触发全局错误中间件:
app.get('/example/getActiveId', async (req, res, next) => { // 从请求里拿id,根据你的实际情况取query或者params const { id } = req.query; // 参数校验,错误直接传给next if (!id) { return next(new Error('缺少必填参数id')) } try { const result = await api.getActiveId(id); res.json({ success: true, result }); } catch (err) { console.error('getActiveId error:', err) // 调用next传入错误,触发全局错误中间件 next(err); } });
3. 可选:统一async路由错误处理
如果项目里async路由很多,每个都写try catch太麻烦,可以写一个通用的包装函数,自动捕获错误传给next:
// 全局定义async路由包装器 const asyncWrap = fn => (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next) } // 路由可以简化成这样,不用写try catch app.get('/example/getActiveId', asyncWrap(async (req, res) => { const { id } = req.query; if (!id) throw new Error('缺少必填参数id') const result = await api.getActiveId(id); res.json({ success: true, result }); }))
验证效果
修改完成后,getActiveId抛出的错误会进入路由的catch块,调用next(err)之后就会触发你写的全局错误处理中间件,返回500和错误信息,不会再出现未处理Promise rejection的警告。
内容的提问来源于stack exchange,提问作者Smith Dwayne
相关产品推荐
相关产品推荐

