node.js 如何在不设置 res headers 两次的情况下处理错误
How to handle errors without setting res headers twice in node.js
我对节点的 req, res
参数以及使用异步调用时处理这些参数的最佳方式感到有点困惑。我目前拥有的一个功能应该是将一个项目添加到我的数据库,相应地更新一些数据库模型,然后发送一个响应说更新成功。但是,如果发生错误,此函数异步调用的函数可能会发送错误的响应。如果发生这种情况,我会收到错误 Can't set headers after they are sent
,因为我正在尝试调用 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);
});
updateItemRating:
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');
}
});
};
您应该抛出一个错误,而不是让您的更新函数发送结果,这样您的外部函数将捕获错误,您可以将其用于 return 它。
另一种思考方式是,您的外部函数正在使用 res.send() 处理成功案例,因此它也应该负责错误案例的 res.send。
您的数据库层对调用者的了解越少,重用我们的代码就越容易。
创建自定义错误类型来封装 404:
function NotFoundError(message) {
this.message = (message || "");
}
NotFoundError.prototype = new 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
的函数调用都是异步的。多次调用响应发送,也不确定首先调用哪个方法发送。为了解决您的问题,我建议您应用以下技术:
回调:您可以将回调作为参数传递,它将执行 res.send
并且您可以在错误或成功条件下调用相同的回调。
UserController.updateItems(req.user._id, result._id,function(status,message){res.status(status).send(message);});
您可以像这样更新项目评分方法:
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);
}
});
});
};
- Async Module :您可以使用此模块同步您的方法调用。
我对节点的 req, res
参数以及使用异步调用时处理这些参数的最佳方式感到有点困惑。我目前拥有的一个功能应该是将一个项目添加到我的数据库,相应地更新一些数据库模型,然后发送一个响应说更新成功。但是,如果发生错误,此函数异步调用的函数可能会发送错误的响应。如果发生这种情况,我会收到错误 Can't set headers after they are sent
,因为我正在尝试调用 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);
});
updateItemRating:
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');
}
});
};
您应该抛出一个错误,而不是让您的更新函数发送结果,这样您的外部函数将捕获错误,您可以将其用于 return 它。
另一种思考方式是,您的外部函数正在使用 res.send() 处理成功案例,因此它也应该负责错误案例的 res.send。
您的数据库层对调用者的了解越少,重用我们的代码就越容易。
创建自定义错误类型来封装 404:
function NotFoundError(message) {
this.message = (message || "");
}
NotFoundError.prototype = new 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
的函数调用都是异步的。多次调用响应发送,也不确定首先调用哪个方法发送。为了解决您的问题,我建议您应用以下技术:
回调:您可以将回调作为参数传递,它将执行
res.send
并且您可以在错误或成功条件下调用相同的回调。UserController.updateItems(req.user._id, result._id,function(status,message){res.status(status).send(message);});
您可以像这样更新项目评分方法:
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);
}
});
});
};
- Async Module :您可以使用此模块同步您的方法调用。