Node.js 在Express route中捕获错误时,如何绕过first res.render以避免错误“发送到客户端后无法设置头”?

Node.js 在Express route中捕获错误时,如何绕过first res.render以避免错误“发送到客户端后无法设置头”?,node.js,express,mongoose,Node.js,Express,Mongoose,背景:下面的简化测试代码使用Express和Mongoose 问题:我设置了.then语句来抛出测试错误。当抛出异常时,我的错误处理中间件将使用next而不是before res.render'index'{doesUserExist}触发;被击中了。这一行导致错误,无法在发送到客户端后设置头,因为在我的错误处理中间件res.render'error_page',{err};也叫。我应该更改代码的哪一部分以消除错误 跟进:我需要的不仅仅是方法上的一点改变吗?我是否使用了完全错误的模式来高效/有效

背景:下面的简化测试代码使用Express和Mongoose

问题:我设置了.then语句来抛出测试错误。当抛出异常时,我的错误处理中间件将使用next而不是before res.render'index'{doesUserExist}触发;被击中了。这一行导致错误,无法在发送到客户端后设置头,因为在我的错误处理中间件res.render'error_page',{err};也叫。我应该更改代码的哪一部分以消除错误

跟进:我需要的不仅仅是方法上的一点改变吗?我是否使用了完全错误的模式来高效/有效地执行此操作

app.get('/', function(req, res, next) {

    (async function() { 
        let doesUserExist = await User.exists( { name: 'steve' })
            .then( function(result) {
                throw 'simulated error';
            })
            .catch( function(error) {
                next(new Error(error));
            });
        res.render('index', { doesUserExist });
    })();
});

app.use(function(err, req, res, next) {

    res.render('error_page', { err });
});

而不是下一次写入返回nextnewerrorerror。这样,它就不会执行任何进一步的代码并转到错误中间件,而不是下一次写入返回nextnewerrorerror。这样,它就不会执行任何进一步的代码并转到错误中间件,这是因为一个没有catch块的异步函数

app.get('/', function (req, res, next) {
    (async function () {
        try {
            let doesUserExist = await User.exists( { name: 'steve' });
            if (doesUserExist) {
                throw 'simulated error';

            } else {
                next(new Error(error));

            }
            res.render('index', { doesUserExist });
        } catch (err) {
            return next(err)
        }
    })();
});

app.use(function (err, req, res, next) {
    res.render('error_page', { err });
});

这是因为异步函数没有catch块

app.get('/', function (req, res, next) {
    (async function () {
        try {
            let doesUserExist = await User.exists( { name: 'steve' });
            if (doesUserExist) {
                throw 'simulated error';

            } else {
                next(new Error(error));

            }
            res.render('index', { doesUserExist });
        } catch (err) {
            return next(err)
        }
    })();
});

app.use(function (err, req, res, next) {
    res.render('error_page', { err });
});

您可以创建一个函数包装器来捕获所有错误并将其发送到错误中间件:

const asyncWrap = fn =>
  function asyncUtilWrap (req, res, next, ...args) {
    const fnReturn = fn(req, res, next, ...args)
    return Promise.resolve(fnReturn).catch(next)
  }
然后,您可以在所有控制器中重新使用它,使应用程序更加干净:

app.get('/', asyncWrap(async function(req, res, next) {
        let doesUserExist = await User.exists( { name: 'steve' }) //*
            .then( function(result) {
                throw 'simulated error'; // This error is automatically sent to next()
            })
            .catch( function(error) {
                next(new Error(error)); // This error works normally
            });
        res.render('index', { doesUserExist });
});

*顺便说一下,您不应该将wait和then/catch语法组合起来。

您可以创建一个函数包装器来捕获所有错误并将它们发送到错误中间件:

const asyncWrap = fn =>
  function asyncUtilWrap (req, res, next, ...args) {
    const fnReturn = fn(req, res, next, ...args)
    return Promise.resolve(fnReturn).catch(next)
  }
然后,您可以在所有控制器中重新使用它,使应用程序更加干净:

app.get('/', asyncWrap(async function(req, res, next) {
        let doesUserExist = await User.exists( { name: 'steve' }) //*
            .then( function(result) {
                throw 'simulated error'; // This error is automatically sent to next()
            })
            .catch( function(error) {
                next(new Error(error)); // This error works normally
            });
        res.render('index', { doesUserExist });
});
*顺便说一下,您不应该将wait和then/catch语法组合在一起