node.js - UnhandledPromiseRejectionWarning:抛出错误时出错
问题描述
我的代码由路由、全局错误处理程序和一个验证函数组成。代码的第一个版本是完全同步的,一切正常。现在我正在尝试将其设为 asyc,因此验证函数如下所示:
const validateGenres = async (genres) => {
const fromDB = await genre.find(); // code here is fine, it always find genres
const validationArr = genres.reduce((acc, e) => {
...code
}, [])
if (validationArr.length !== 0) {
throw new ValidationError(`Missing genres ${validationArr}`); //this error causes UnhandledPromiseRejectionWarning
}
return genres;
}
为了捕获所有错误,我创建了全局错误处理程序:
async function errorHandler(err, req, res, next) {
logger.log({ message: err, level: 'error' });
if (err instanceof CustomError) {
return res.status(err.statusCode).send({ errors: err.serializeErrors() });
}
res.status(400).send({
errors: [{ message: 'Something went wrong' }]
});
}
问题是,现在每当抛出新的 ValidationError 时,它都不会去执行 errorHandler 而是会抛出:
(node:11253) UnhandledPromiseRejectionWarning: Error
at validateGenres (/home/mat/Projects/-task-v3/-task-v3/src/middlewares/schema-validator.js:16:15)
at async /home/mat/Projects/-task-v3/-task-v3/src/routes/findAll.js:19:28
findAll 基本上是路由器端点,如下所示:
router.get('/api/movies/findAll/:runtime?/:genres?', async (req, res) => {
movies = await movie.find(params);
res.status(200).json(movies)
})
更重要的是,注册全局错误处理程序我已经这样做了:
const app = express();
app.use(json());
app.use(findAllRouter);
app.use(createRouter);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.all('*', async (req, res) => {
res.status(404).json({ "errors": [ { "message": "No such endpoint" } ] })
});
app.use(errorHandler);
const start = () => app.listen(PORT, () => { console.log(`Listening on port ${PORT}`) });
module.exports = { start }
解决方案
async
在 express 中使用函数作为中间件回调时要小心。Express 不会在async
回调函数中捕获您未捕获的异常,您将获得UnhandledPromiseRejectionWarning
.
如果要async
回调,可以执行以下操作:
// Declare on this wrapper function
function callbackWrap(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
// And use it in your code
router.get('/api/movies/findAll/:runtime?/:genres?', callbackWrap(async (req, res) => {
movies = await movie.find(params);
res.status(200).json(movies)
}))
也为您做errorHandler
(尽管如果async
不需要,最好将其删除)
推荐阅读
- c# - 删除列包含特定文本的行
- android - Android Studio如何为资源生成id
- selenium - reCAPTCHA 3 如何知道我正在使用 Selenium/chromedriver?
- c# - 如何从没有标题但具有特定格式的文本文件构建模型
- sql - 从特定列中删除逗号(',')而不是从 SQL Server 中的完整表中删除
- sql - SQL 更新 tableA.column,其中列和值位于单独的表中
- html - CSS 网格,一些媒体查询不适用
- javascript - 使用 lodash 检索嵌套元素值
- git - 在协作项目中保持分叉与上游同步的标准方法是什么?
- sql - 在 SQL 中使用 rank()