Javascript express异步中间件中的错误处理

Javascript express异步中间件中的错误处理,javascript,node.js,express,es6-promise,Javascript,Node.js,Express,Es6 Promise,我在express中有一个async中间件,因为我想在其中使用wait来清理代码 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 = awai

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

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);
});
因此,我得到了
未处理的PromisejectionWarning
,而不是进入我的错误处理中间件,我如何让错误冒泡出来,并用express处理它

问题是,当它拒绝时,它不会导致我的错误 中间件,但如果我删除async关键字并在 是的

app.get('/route', (req, res, next) => {
    throw new Error('Error');
    res.end(result);
});
express
目前不支持承诺,支持可能会在未来发布的
express@5.x.x

因此,当您传递中间件函数时,
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
处理程序,因此会收到
未处理的PromiserEjectionWarning


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

但是,如果您有大量的
async
middleware,它可能会有点重复

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

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

还有一些软件包可以使用


使用asyncHandler进行应答是好的和有用的,但是在每个路由中编写这个包装器仍然不太舒服。我建议作出改善:

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

const methods = [
    'get',
    'post',
    'delete'  // & etc.
]

function toAsyncRouter(router) {
    for (let key in router) {
        if (methods.includes(key)) {
            let method = router[key]
            router[key] = (path, ...callbacks) => method.call(router, path, ...callbacks.map(cb => asyncHandler(cb)))
        }
    }
    return router
}
现在我们可以这样做:

const router = toAsyncRouter(express().Router())
router.get('/', someAsyncController)
还有一个


几分钟前添加了一个npm模块。

您需要使用try catch,在catch部分只需像下面这样传递next()参数中的错误-

async create(req, res, next) {

    try {
      const userProp = req.body;
      const user = new User(userProp)

      const response = await user.save()
      const token = await user.createJWSToken()

      res.send({response, token})

    } catch (err){
      next(err)
    }
}
显然,将这个express中间件放在index.js文件中

app.use((err, req, res, next) => {
  res.status(422).send({ error: err.message });
});
嗯,我找到了这个-,然后需要脚本,你就可以开始了

const express = require('express');
require('express-async-errors');

您需要回调异步处理程序。如果你知道promisify的概念,这是相反的。Callbackify是内置的节点

import util from 'util'

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

它的作用是返回一个带有第三个参数的函数,第三个参数将是下一个函数,并在解析承诺后调用它。如果承诺被拒绝,将调用下一个函数,并将错误作为参数。

Express 5现在处理异步承诺:

从Express5开始,路由处理程序和中间件返回 Promise在拒绝或抛出时将自动调用next(值) 一个错误。比如说


还值得一提的是,框架(据说是由第一次使用Express的人构建的)为请求处理程序中的异步操作提供了更多的内置便利,以及OP所要求的承诺感知和错误处理方式。类型脚本:
export const asynchHandler=(fn:RequestHandler)=>(请求:请求,回复:响应,下一步:下一步功能)=>Promise.resolve(fn(请求,回复,下一步)).catch(下一步)
。谢谢!有关
express@5.x.x
支持:。我已经尝试了
5.0.0-alpha.8
,它的工作原理与描述完全相同:
返回承诺的路由处理程序和中间件将调用next(value)当他们拒绝或抛出错误时自动执行。
。我在谷歌搜索时发现了一篇好文章:此模块仍然有用。如下所述,Express v5将添加对异步中间件的支持,但到目前为止,还没有v5的发布。