Express + Mongoose:无法在回调中发送响应
Express + Mongoose: Cannot send response in callback
我已经对这个问题感到沮丧超过 24 小时,我已经将问题范围缩小到:
在下面的代码中,我正在使用 mongoose 更新 MongoDB 文档,并且在成功更新后,我 return 通过快速响应 json 对象。当我尝试在猫鼬的回调中调用响应时出现以下错误。
数据库更新成功,我从回调中取回数据,一切正常,除了发送响应说一切都很好。
在此之前我没有发送回复,也没有在发送之前以任何方式触摸 res
对象。我正在寻求有关如何在成功回调后发送响应的帮助。
错误:
Updating user draftBooks
/home/samuel/Documents/Github/Moirai/node_modules/mongoose/lib/utils.js:419
throw err;
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11)
at ServerResponse.header (/home/samuel/Documents/Github/Moirai/node_modules/express/lib/response.js:719:10)
at ServerResponse.send (/home/samuel/Documents/Github/Moirai/node_modules/express/lib/response.js:164:12)
at ServerResponse.json (/home/samuel/Documents/Github/Moirai/node_modules/express/lib/response.js:250:15)
at Promise.<anonymous> (/home/samuel/Documents/Github/Moirai/server/lib/stories.js:105:13)
at Promise.<anonymous> (/home/samuel/Documents/Github/Moirai/node_modules/mongoose/node_modules/mpromise/lib/promise.js:162:8)
at emitOne (events.js:77:13)
at Promise.emit (events.js:169:7)
at Promise.emit (/home/samuel/Documents/Github/Moirai/node_modules/mongoose/node_modules/mpromise/lib/promise.js:79:38)
at Promise.fulfill (/home/samuel/Documents/Github/Moirai/node_modules/mongoose/node_modules/mpromise/lib/promise.js:92:20)
猫鼬模式:
var Schema = mongoose.Schema;
// create user schema
var userSchema = new Schema({
user_id: String,
username: String,
password: String,
draftBooks: [{book_id: String}]
});
// add draftBook
userSchema.methods.addDraftBook = function (book_id, callback) {
return this.model('User').findOneAndUpdate(
{ _id: this.user_id }, // search query
{ $push: { 'draftBooks': {'_id': book_id.toString()} } }, // update action
{ upsert: true },
callback
);
}
快速路线:
router.route('/')
.post((req, res, next) => {
// other stuff that works great
// req.storyData defined here
})
.post((req, res) => {
// create update corresponding user
console.log("Updating user draftBooks");
// res.json({}) works outside of callback
var userData = new user({ user_id: req.storyData.creator });
userData.addDraftBook(req.storyData._id, (err, data) => {
if (err){
res.json({message: err});
} else {
res.json({message: "Should work"}); //gives error
}
});
});
这让我很沮丧,我没有发现任何语法错误,我错过了什么?
好的,所以在打印出来的错误信息中我们发现:Can't set headers after they're sent.
在您的快速路线中,您已经写了两次 res.json({});
。您似乎正在从 mongoose 方法接收到正确的数据。然后你调用 res.json({message: 'gives error'});
。正如您所说,当调用 next() 时发生这种情况,因为您明确告诉它。在您当前编写的地方写一个 if-else
语句来处理错误,如下所示:
blah blah (err, data) => {
if (err) {
res.json({ success: false, message: 'Gives error' });
} else {
res.json({ success: true, data: data });
}
});
取出最后一个res.json
调用。您不需要它,因为您已经在回调中将其发回。在 Express 路由的上下文中,res 是一个具有词法作用域的对象(我认为),并且由于它是在上面的作用域中定义的,所以您可以在嵌套函数中访问它。因此,当您在回调中发送它时,您是在为整个 POST 请求发送它。
你的问题是这一行:
res.json({message: "returns this response"})
在
之前运行
res.json({message: "Gives error"}).
所以你已经在 res 中设置了 json,这就是你得到错误的原因。
您不能设置 header 两次。给 res.json() 赋值两次(回调内 1 次,回调外 1 次)
没有多大意义
为什么不这样做:
userData.addDraftBook(req.storyData._id, (err, data) => {
if (!err)
res.json({message: "successful data"})
else
res.json({message: "returns this response"})
});
我已经对这个问题感到沮丧超过 24 小时,我已经将问题范围缩小到:
在下面的代码中,我正在使用 mongoose 更新 MongoDB 文档,并且在成功更新后,我 return 通过快速响应 json 对象。当我尝试在猫鼬的回调中调用响应时出现以下错误。
数据库更新成功,我从回调中取回数据,一切正常,除了发送响应说一切都很好。
在此之前我没有发送回复,也没有在发送之前以任何方式触摸 res
对象。我正在寻求有关如何在成功回调后发送响应的帮助。
错误:
Updating user draftBooks
/home/samuel/Documents/Github/Moirai/node_modules/mongoose/lib/utils.js:419
throw err;
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11)
at ServerResponse.header (/home/samuel/Documents/Github/Moirai/node_modules/express/lib/response.js:719:10)
at ServerResponse.send (/home/samuel/Documents/Github/Moirai/node_modules/express/lib/response.js:164:12)
at ServerResponse.json (/home/samuel/Documents/Github/Moirai/node_modules/express/lib/response.js:250:15)
at Promise.<anonymous> (/home/samuel/Documents/Github/Moirai/server/lib/stories.js:105:13)
at Promise.<anonymous> (/home/samuel/Documents/Github/Moirai/node_modules/mongoose/node_modules/mpromise/lib/promise.js:162:8)
at emitOne (events.js:77:13)
at Promise.emit (events.js:169:7)
at Promise.emit (/home/samuel/Documents/Github/Moirai/node_modules/mongoose/node_modules/mpromise/lib/promise.js:79:38)
at Promise.fulfill (/home/samuel/Documents/Github/Moirai/node_modules/mongoose/node_modules/mpromise/lib/promise.js:92:20)
猫鼬模式:
var Schema = mongoose.Schema;
// create user schema
var userSchema = new Schema({
user_id: String,
username: String,
password: String,
draftBooks: [{book_id: String}]
});
// add draftBook
userSchema.methods.addDraftBook = function (book_id, callback) {
return this.model('User').findOneAndUpdate(
{ _id: this.user_id }, // search query
{ $push: { 'draftBooks': {'_id': book_id.toString()} } }, // update action
{ upsert: true },
callback
);
}
快速路线:
router.route('/')
.post((req, res, next) => {
// other stuff that works great
// req.storyData defined here
})
.post((req, res) => {
// create update corresponding user
console.log("Updating user draftBooks");
// res.json({}) works outside of callback
var userData = new user({ user_id: req.storyData.creator });
userData.addDraftBook(req.storyData._id, (err, data) => {
if (err){
res.json({message: err});
} else {
res.json({message: "Should work"}); //gives error
}
});
});
这让我很沮丧,我没有发现任何语法错误,我错过了什么?
好的,所以在打印出来的错误信息中我们发现:Can't set headers after they're sent.
在您的快速路线中,您已经写了两次 res.json({});
。您似乎正在从 mongoose 方法接收到正确的数据。然后你调用 res.json({message: 'gives error'});
。正如您所说,当调用 next() 时发生这种情况,因为您明确告诉它。在您当前编写的地方写一个 if-else
语句来处理错误,如下所示:
blah blah (err, data) => {
if (err) {
res.json({ success: false, message: 'Gives error' });
} else {
res.json({ success: true, data: data });
}
});
取出最后一个res.json
调用。您不需要它,因为您已经在回调中将其发回。在 Express 路由的上下文中,res 是一个具有词法作用域的对象(我认为),并且由于它是在上面的作用域中定义的,所以您可以在嵌套函数中访问它。因此,当您在回调中发送它时,您是在为整个 POST 请求发送它。
你的问题是这一行:
res.json({message: "returns this response"})
在
之前运行res.json({message: "Gives error"}).
所以你已经在 res 中设置了 json,这就是你得到错误的原因。 您不能设置 header 两次。给 res.json() 赋值两次(回调内 1 次,回调外 1 次)
没有多大意义为什么不这样做:
userData.addDraftBook(req.storyData._id, (err, data) => {
if (!err)
res.json({message: "successful data"})
else
res.json({message: "returns this response"})
});