如何在node.js中处理错误而不设置两次res头

如何在node.js中处理错误而不设置两次res头,node.js,express,asynchronous,response-headers,Node.js,Express,Asynchronous,Response Headers,当我使用异步调用时,我对节点的req,res参数以及处理这些参数的最佳方法有点困惑。我目前拥有的一个函数应该是向我的数据库添加一个项,相应地更新一些数据库模型,然后发送一个响应,说更新成功。但是,如果发生错误,此函数异步调用的函数可能会发送错误响应。如果发生这种情况,则会出现错误发送后无法设置标题,因为我尝试调用res.send两次。如果有人能帮助我们找出一种处理错误的最佳方法,我们将不胜感激。谢谢 主要功能: item.author = req.user._id; item.descripti

当我使用异步调用时,我对节点的
req,res
参数以及处理这些参数的最佳方法有点困惑。我目前拥有的一个函数应该是向我的数据库添加一个项,相应地更新一些数据库模型,然后发送一个响应,说更新成功。但是,如果发生错误,此函数异步调用的函数可能会发送错误响应。如果发生这种情况,则会出现错误
发送后无法设置标题
,因为我尝试调用
res.send
两次。如果有人能帮助我们找出一种处理错误的最佳方法,我们将不胜感激。谢谢

主要功能:

item.author = req.user._id;
item.description = req.query.description;
item.rating = req.query.rating;

item.save()
    .then(result => {
        // update user's items
        UserController.updateItems(req.user._id, result._id);
        ItemController.updateItemRating(req.query.outingId, req.query.rating, res);
        res.send(result);
    })
    .catch(error => {
        res.send(error);
    });
export const updateItemRating = (itemId, rating, res) => {
Item.findOne({ _id: itemId }).exec((err, item) => {
    if (item === undefined || item === null) {
        throw new NotFoundError('Item not found; check item ID');
    }

    Item.findOneAndUpdate(
        { _id: itemId },
        { $set: { rating: rating },
        },
        (error, item) => {
            if (error) {
                throw new NotFoundError('Error updating item with new rating');
            }
        });
    });
};
更新配置:

export const updateItemRating = (itemId, rating, res) => {
    Item.findOne({ _id: itemId }).exec((err, item) => {
        if (item === undefined || item === null) {
            return res.status(404).send('Item not found; check item ID');
        }

        Item.findOneAndUpdate(
            { _id: itemId },
            { $set: { rating: rating },
            },
            (error, item) => {
                if (error) {
                    res.status(404).send('Error updating item with new rating');
                }
            });
    });
};
更新项目:

export const updateItems = (userId, itemId) => {
    User.findOneAndUpdate(
        { _id: userId },
        { $push: { items: [itemId] } },
        (err, user) => {
            console.log('user' + user);
            if (err) {
                console.log('got an error in updateItems');
            }
        });
};

您不应该让更新函数发送结果,而应该抛出()一个错误,这样外部函数将捕获错误,您可以使用它返回错误

考虑这一点的另一种方式是,外部函数使用res.send()处理成功案例,因此它还应该负责错误案例的res.send

数据库层对调用方的了解越少,就越容易重用我们的代码

创建自定义错误类型以封装404:

function NotFoundError(message) {
  this.message = (message || "");
}
NotFoundError.prototype = new Error();
然后在你的内在功能中使用它:

item.author = req.user._id;
item.description = req.query.description;
item.rating = req.query.rating;

item.save()
    .then(result => {
        // update user's items
        UserController.updateItems(req.user._id, result._id);
        ItemController.updateItemRating(req.query.outingId, req.query.rating, res);
        res.send(result);
    })
    .catch(error => {
        res.send(error);
    });
export const updateItemRating = (itemId, rating, res) => {
Item.findOne({ _id: itemId }).exec((err, item) => {
    if (item === undefined || item === null) {
        throw new NotFoundError('Item not found; check item ID');
    }

    Item.findOneAndUpdate(
        { _id: itemId },
        { $set: { rating: rating },
        },
        (error, item) => {
            if (error) {
                throw new NotFoundError('Error updating item with new rating');
            }
        });
    });
};
你的主要目标是:

item.save()
.then(result => {
    // update user's items
    UserController.updateItems(req.user._id, result._id);
    ItemController.updateItemRating(req.query.outingId, req.query.rating, res);
    res.send(result);
})
.catch(error => {
    if (error instanceof NotFoundError) {
       res.status(404).send(error.message);
    }
    else {
       res.send(error);
    }
});

您不应该让更新函数发送结果,而应该抛出()一个错误,这样外部函数将捕获错误,您可以使用它返回错误

考虑这一点的另一种方式是,外部函数使用res.send()处理成功案例,因此它还应该负责错误案例的res.send

数据库层对调用方的了解越少,就越容易重用我们的代码

创建自定义错误类型以封装404:

function NotFoundError(message) {
  this.message = (message || "");
}
NotFoundError.prototype = new Error();
然后在你的内在功能中使用它:

item.author = req.user._id;
item.description = req.query.description;
item.rating = req.query.rating;

item.save()
    .then(result => {
        // update user's items
        UserController.updateItems(req.user._id, result._id);
        ItemController.updateItemRating(req.query.outingId, req.query.rating, res);
        res.send(result);
    })
    .catch(error => {
        res.send(error);
    });
export const updateItemRating = (itemId, rating, res) => {
Item.findOne({ _id: itemId }).exec((err, item) => {
    if (item === undefined || item === null) {
        throw new NotFoundError('Item not found; check item ID');
    }

    Item.findOneAndUpdate(
        { _id: itemId },
        { $set: { rating: rating },
        },
        (error, item) => {
            if (error) {
                throw new NotFoundError('Error updating item with new rating');
            }
        });
    });
};
你的主要目标是:

item.save()
.then(result => {
    // update user's items
    UserController.updateItems(req.user._id, result._id);
    ItemController.updateItemRating(req.query.outingId, req.query.rating, res);
    res.send(result);
})
.catch(error => {
    if (error instanceof NotFoundError) {
       res.status(404).send(error.message);
    }
    else {
       res.send(error);
    }
});

updateItems
updateItemRating
的函数调用都是异步的。Response send被多次调用,并且不确定首先调用哪个方法send。要解决您的问题,我建议您应用以下技巧:

  • 回调:您可以将回调作为参数传递,该参数将执行
    res.send
    ,在出现错误或成功情况时,您可以调用相同的回调

    UserController.updateItems(请求用户id、结果id、函数(状态、消息){res.status(状态)、send(消息);})

  • 您可以更新项目评级方法,如:

    export const updateItemRating = (itemId, rating, callback) => {
        Item.findOne({ _id: itemId }).exec((err, item) => {
            if (item === undefined || item === null) {
                callback(404,'Item not found; check item ID');    
            }    
            Item.findOneAndUpdate(
                { _id: itemId },
                { $set: { rating: rating },
                },
                (error, item) => {
                    if (error) {
                         callback(404,'Error updating item with new rating'); 
                    }else{
                        callback(200);
                    }
                });
        });
    };
    
  • :您可以使用此模块同步方法调用
    updateItems
    updateItemRating
    的函数调用都是异步的。Response send被多次调用,并且不确定首先调用哪个方法send。要解决您的问题,我建议您应用以下技巧:

  • 回调:您可以将回调作为参数传递,该参数将执行
    res.send
    ,在出现错误或成功情况时,您可以调用相同的回调

    UserController.updateItems(请求用户id、结果id、函数(状态、消息){res.status(状态)、send(消息);})

  • 您可以更新项目评级方法,如:

    export const updateItemRating = (itemId, rating, callback) => {
        Item.findOne({ _id: itemId }).exec((err, item) => {
            if (item === undefined || item === null) {
                callback(404,'Item not found; check item ID');    
            }    
            Item.findOneAndUpdate(
                { _id: itemId },
                { $set: { rating: rating },
                },
                (error, item) => {
                    if (error) {
                         callback(404,'Error updating item with new rating'); 
                    }else{
                        callback(200);
                    }
                });
        });
    };
    
  • :您可以使用此模块同步方法调用
    您正试图将
    updateItemRating
    作为同步函数执行,而这是一个异步函数。你应该连锁承诺,然后在最后只使用一个
    res.send
    。或者使用async/wait,您尝试将
    updateItemRating
    作为同步函数执行,而这是一个异步函数。你应该连锁承诺,然后在最后只使用一个
    res.send
    。或者使用async/Await,我正试图按照您的建议实现,但最终得到一个以
    Error:Item not found开头的堆栈跟踪;检查项目ID。
    捕获来自Mongoose查询的错误是否有问题?我不确定出了什么问题以及为什么我不能正确地捕获错误。我只是注意到我的示例中有一个输入错误-已更新为更正-NotFound.prototype应该是NotFoundError.prototypeYes-我实际上捕获到了这个错误,并在我的应用程序中将其更改为
    NotFoundError
    ,但它仍然不起作用。看起来它成功地抛出了错误(因为堆栈跟踪正在被打印),但我从未输入catch语句(
    console.log
    这里没有向console打印任何内容)。我正在尝试按照您的建议实现,但最终得到的堆栈跟踪以
    error:Item not found;检查项目ID。
    捕获来自Mongoose查询的错误是否有问题?我不确定出了什么问题以及为什么我不能正确地捕获错误。我只是注意到我的示例中有一个输入错误-已更新为更正-NotFound.prototype应该是NotFoundError.prototypeYes-我实际上捕获到了这个错误,并在我的应用程序中将其更改为
    NotFoundError
    ,但它仍然不起作用。看起来它成功地抛出了错误(因为堆栈跟踪正在打印),但我从未输入catch语句(
    console.log
    这里没有向console打印任何内容)。谢谢!我最终使用了Async
    series
    并按照您的建议应用了回调,现在一切正常了。谢谢!我最终使用了Async
    series
    并按照您的建议应用了回调,现在就可以了。