Express + Mongoose:无法在回调中发送回复

时间:2017-02-08 22:22:35

标签: express mongoose callback response mongoose-schema

我对此问题感到沮丧超过24小时,我已将此问题缩小到这个范围:

在下面的代码中,我使用mongoose更新MongoDB文档,并且在成功更新后,我通过快速响应返回一个json对象。当我尝试在mongoose的回调中调用响应时,我收到以下错误。

数据库中的更新成功,我从回调中获取数据,一切正常,除了发送响应说一切都很棒。

我之前没有发送回复,也不会在发送之前以任何方式触摸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)

Mongoose Schema:

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
        }
      });
  });

这让我非常沮丧,我没有看到任何语法错误,我错过了什么?

2 个答案:

答案 0 :(得分:0)

好的,所以在打印出的错误消息中我们找到: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请求发送它。

答案 1 :(得分:0)

你的问题是这一行:

res.json({message: "returns this response"})

之前运行
res.json({message: "Gives error"}).

所以你已经在res里面设置了json,这就是你得到错误的原因。 你不能两次设置标题。为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"})
  });