我在express中有一个async中间件,因为我想在其中使用await来清理代码.

const express = require('express');
const app = express();

app.use(async(req, res, next) => {
    await authenticate(req);
    next();
});

app.get('/route', async(req, res) => {
    const result = await request('http://example.com');
    res.end(result);
});

app.use((err, req, res, next) => {

    console.error(err);

    res
        .status(500)
        .end('error');
})

app.listen(8080);

问题是,当它拒绝时,它不会转到我的错误中间件,但如果我删除中间件中的async关键字和throw,它就会转到.

app.get('/route', (req, res, next) => {
    throw new Error('Error');
    res.end(result);
});

所以我得到UnhandledPromiseRejectionWarning,而不是进入我的错误处理中间件,我如何让错误冒泡,并表示处理它?

推荐答案

问题是,当它拒绝时,它不会导致我的错误

express目前不支持promise ,支持可能会出现在express@5.x.x的future 版本中

所以当你传递一个中间件函数时,express将在try/catch块中调用它.

Layer.prototype.handle_request = function handle(req, res, next) {
  var fn = this.handle;

  if (fn.length > 3) {
    // not a standard request handler
    return next();
  }

  try {
    fn(req, res, next);
  } catch (err) {
    next(err);
  }
};

问题是,try/catch不会捕获async函数之外的Promise拒绝,而且由于express不会向中间件返回的Promise添加.catch处理程序,因此会得到UnhandledPromiseRejectionWarning.


简单的方法是在中间件中添加try/catch,然后调用next(err).

app.get('/route', async(req, res, next) => {
    try {
        const result = await request('http://example.com');
        res.end(result);
    } catch(err) {
        next(err);
    }
});

但是如果你有很多async个中间产品,它可能有点重复.

因为我喜欢我的中间件尽可能干净,而且我通常会让错误冒出来,所以我在async个中间件周围使用一个包装器,如果promise 被拒绝,它将调用next(err),到达快速错误处理程序并避免UnhandledPromiseRejectionWarning

const asyncHandler = fn => (req, res, next) => {
    return Promise
        .resolve(fn(req, res, next))
        .catch(next);
};

module.exports = asyncHandler;

现在你可以这样称呼它:

app.use(asyncHandler(async(req, res, next) => {
    await authenticate(req);
    next();
}));

app.get('/async', asyncHandler(async(req, res) => {
    const result = await request('http://example.com');
    res.end(result);
}));

// Any rejection will go to the error handler

还有一些软件包可以使用

Node.js相关问答推荐

如何使用jq将依赖项添加到package.json中

从目录中获取所有文件,而不是NodeJS中的单个文件

带有apache Couch-db和Nano的推荐引擎:过滤特定用户的视图

如何从谷歌云中部署的应用程序连接到mongoDB Atlas?

如何在Node.js的telegraf.js命令中添加参数?

Solidity 将数据位置从内存更改为存储

Nodejs mongoose 在一个查询中从多个集合中获取结果

简单的 Node js 程序但执行顺序似乎不同?

如何刷新 youtube-data-api v3 的访问令牌

在 gatsby 中安装软件包时不推荐使用的错误

Node.js mongodb 驱动程序异步/等待查询

如何在 MongoDB collection.find() 上获取回调

AWS Kinesis 中的分区键是什么?

socket.io 发出回调合适吗?

将变量传递给nodemailer中的html模板

在 Jade 包含中使用变量

在 Node.js 中使用公钥加密数据

Firestore:多个条件 where 子句

避免在弹性 beantalk 中重建 node_modules

node/nodemon 中是否有对 typescript 的源映射支持?