代码之家  ›  专栏  ›  技术社区  ›  Marcos Casagrande

在Express异步中间件中处理错误

  •  2
  • Marcos Casagrande  · 技术社区  · 6 年前

    我有一个 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);
    

    问题是当它拒绝时,它不会转到我的错误中间件,但是如果我删除 异步的 关键字和 throw 在中间件中是这样的。

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

    所以我要 UnhandledPromiseRejectionWarning 我不能进入我的错误处理中间件,而应该如何让错误冒泡,并表示处理它?

    1 回复  |  直到 6 年前
        1
  •  7
  •   Marcos Casagrande    6 年前

    问题是,当它拒绝时,它不属于我的错误 中间件,但是如果我移除Async关键字并在 它的中间件。

    express 目前不支持承诺,将来可能会发布 express@5.x.x

    所以当您传递中间件函数时, 表达 会在一个 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);
      }
    };
    

    问题是 尝试/捕获 不会抓到 Promise 拒绝 async 函数和自 表达 不添加 .catch 处理程序到 承诺 通过中间件返回,您将得到 UnhandledPromiseRejectionWarning .


    简单的方法是 尝试/捕获 在中间件中,调用 next(err) .

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

    但是如果你有很多 异步的 中间商,可能有点重复。

    因为我喜欢尽可能干净的中间产品,而且我通常让错误冒出来,所以我用包装纸包装 异步的 中间商,这将调用 下一个(错误) 如果承诺被拒绝,请联系明示错误处理程序并避免 未处理的PromiseRejection警告

    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
    

    还有一些包可以使用