Express+;Mongoose:无法在回调中发送响应

Express+;Mongoose:无法在回调中发送响应,express,mongoose,callback,response,mongoose-schema,Express,Mongoose,Callback,Response,Mongoose Schema,我对这个问题感到沮丧已经超过24小时了,我已经将问题缩小到: 在下面的代码中,我正在使用mongoose更新MongoDB文档,更新成功后,我将通过express响应返回一个json对象。当我试图在mongoose的回调中调用中的响应时,出现以下错误 数据库中的更新是成功的,我从回调中得到了数据,一切正常,除了发送响应说一切都很好 在此之前,我不会发送响应,也不会在发送之前以任何方式触摸res对象。我正在寻求有关如何在成功回调时发送响应的帮助 错误: Updating user draftBoo

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

在下面的代码中,我正在使用mongoose更新MongoDB文档,更新成功后,我将通过express响应返回一个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)
快线:

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

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

好的,所以在打印出来的错误消息中,我们发现:
发送后无法设置标题。

在快速路径中,您编写了
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,这就是为什么会出现错误。 不能设置两次标题。两次给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"})
  });

此结构反映了我的原始设置,但无法解决回调中出现的错误问题。将
res.json
放在条件语句中仍然会导致错误。我在回调之外添加了响应,以显示响应在这里有效,但在回调中无效。我会更新它,因为它可能会让人困惑(因为它可以被视为错误的原因,但事实并非如此)。嗯,我正在工作,您的模式方法与我通常编写它的方式有很大的不同,因此我不能花太多时间来找出答案。但是为什么要创建变量
userData
?我会重新编写这个命令,查询Mongo数据库以获取用户,然后直接对获取的用户调用schema方法。承诺链或异步npm模块可以帮助您为此编写干净的代码。最后,我确实可以告诉您,“发送后无法设置头”来自于在多个位置发送
res.json
。没有其他方式可以发生这种情况。我将深入研究模式,看看是否可以确定原因。我一直在玩弄去承诺的想法,我想如果我要分享我的代码,我会这么做。不过,我怀疑是否发送了响应,我有一个404响应,它运行在路径的最末端(调试时注释掉),它检查
res.headersSent
是否发送了任何内容。这是错误的,除了没有收到响应(请求端post失败)之外,它使我认为实际上没有发送响应。我添加了这一行
res.json({message:“returns This response”})
,以显示响应在回调之外工作。错误仍然发生在回调内部。我将删除此项,以便更清楚地强调这一问题。删除这一行会导致以下错误
无法发布/api/route
,这中断了我的测试。我已经尝试了你的代码,用其他异步函数(我使用了“request”)替换userData.addDraftBook,效果很好。
     userData.addDraftBook(req.storyData._id, (err, data) => {
    if (!err)
        res.json({message: "successful data"})
    else
       res.json({message: "returns this response"})
  });