ERR_HTTP_HEADERS_SENT:将标头发送到客户端后无法设置标头

时间:2018-08-31 20:32:23

标签: node.js express mongoose passport.js express-jwt

当与Passport.js,Express和Mongoose一起使用时,我在NodeJS中遇到这个奇怪的问题。基本上,即使我发送的报头不止一个,我也会收到一条错误消息:“在将报头发送到客户端后无法设置报头”。

我还阅读了其他文章并对其进行了尝试,但没有一个起作用。

我已经解决了github问题,但似乎找不到解决方案。我遇到这样的问题,当我发送多个响应头时会触发此错误,但事实是我没有发送多个头。似乎很奇怪。

这是我的堆栈跟踪:

  

(节点:9236)DeprecationWarning:不建议使用当前URL字符串解析器,并且在以后的版本中将其删除。要使用新的解析器,请将选项{useNewUrlParser:true}传递给MongoClient.connect。

     

服务器在端口5000上运行
  MongoDB连接错误
  [ERR_HTTP_HEADERS_SENT]:将标头发送到   客户
  在validateHeader(_http_outgoing.js:503:11)
  在ServerResponse.setHeader(_http_outgoing.js:510:3)
  在ServerResponse.header(/Users/lourdesroashan/code/github/devlog/node_modules/express/lib/response.js:767:10)
  在ServerResponse.json(/Users/lourdesroashan/code/github/devlog/node_modules/express/lib/response.js:264:10)
  位于Profile.findOne.then.profile(/Users/lourdesroashan/code/github/devlog/routes/api/profile.js:27:30)
  在

这是我的服务器代码:

router.get("/userprofile", passport.authenticate('jwt', { session: false }), (req, res) => {

  Profile.findOne({ user: req.user.id }).then(profile => {
    if (!profile) {
      return res.status(404).json({ error: "No Profile Found" });
    }
    else {
      res.json(profile);
    }
  }).catch(err => {
    console.log(err);
  })
});

我了解错误的含义,但据我所知,我认为我没有发送多个标头,甚至通过console.log检查是否仅运行了一个块。

非常感谢您! :)

完整代码位于:https://github.com/lourdesr/devlog

编辑:

我知道了。尝试获取经过身份验证的用户时,我的passport.js出现问题。我忘了在造成这种情况的“完成”方法上使用“返回”。刚刚添加了return语句就可以了!

8 个答案:

答案 0 :(得分:9)

每当您尝试向同一请求发送多个响应时,就会发生该特定错误,通常是由不正确的异步代码引起的。

您在问题中显示的代码似乎不会导致该错误,但是我确实在不同的路由here中看到了会导致该错误的代码。

在这里:

if (!user) {
  errors.email = "User not found";
  res.status(404).json({ errors });
}

您需要将其更改为:

if (!user) {
  errors.email = "User not found";
  res.status(404).json({ errors });
  // stop further execution in this callback
  return;
}

完成res.status(404).json({ errors });后,您不希望代码继续执行,因为它随后将尝试发送另一个响应。


此外,到处都是:

if (err) throw err;

在异步回调中,您需要将其替换为实际发送错误响应的内容,例如:

if (err) {
    console.log(err);
    res.sendStatus(500);
    return;
}

抛出到异步回调中的代码只是返回到node.js事件系统中,并没有抛出到您可以实际捕获的任何地方。此外,它不会发送对http请求的响应。换句话说,它实际上并没有执行服务器应该执行的操作。因此,请帮自己一个忙,不要在服务器中编写该代码。遇到错误时,请发送错误响应。


由于您似乎是陌生人,因此我想在https://github.com/lourdesr/devlog上包含指向完整源代码的链接,这是对您的称赞,因为只有通过查看,我才能看到此地方错误发生。

答案 1 :(得分:1)

对不起,我的回复很晚, 根据猫鼬文档“猫鼬查询不是promise。为方便起见,它们具有用于co和async / await的.then()函数。但是,与promise不同,调用查询的.then()可以多次执行查询。” < / p>

所以要使用诺言

mongoose.Promise = global.Promise //To use the native js promises

然后

var promise = Profile.findOne({ user: req.user.id }).exec()
promise.then(function (profile){
    if (!profile) {
      throw new Error("User profile not found") //reject promise with error
    }
    return res.status(200).json(profile) //return user profile      
}).catch(function (err){
    console.log(err); //User profile not found
    return res.status(404).json({ err.message }) //return your error msg
})

这是一篇不错的关于switching out callbacks with promises in Mongoose

的文章

关于猫鼬的答案承诺拒绝处理Mongoose right promise rejection handling

答案 2 :(得分:1)

在HBS模板引擎中使用express和mongoose时出现相同的错误。我去Expressjs并阅读res.render的文档,它说//如果指定了回调,则必须显式发送呈现的HTML字符串。因此,我最初并没有在回调中显式发送html。这仅适用于联系表格,尽管已登录,但不适用于登录信息

//Original
let { username, email } = req.query;  //My get query data easier to read

res.status(200).render('index', { username, email });

//Solution without error. Second param sending data to views, Third param callback

res.status(200).render('index', { username, email }, (err, html)=>{
      res.send(html);
 });

答案 3 :(得分:0)

由于一个愚蠢的错误,我收到此错误。在引用其他工作代码时,我需要格外小心。真正令人尴尬的部分是我花了多长时间试图找出错误的原因。 uf!

坏:

return res
  .send(C.Status.OK)
  .json({ item });

好:

return res
  .status(C.Status.OK)
  .json({ item });

答案 4 :(得分:0)

您必须在程序中启用Promises,在我的情况下,我使用mongoose.Promise = global.Promise在猫鼬模式中启用了它。 这样可以使用native js promises

此解决方案的其他替代方法是:

var mongoose = require('mongoose');
// set Promise provider to bluebird
mongoose.Promise = require('bluebird');

// q
mongoose.Promise = require('q').Promise;

但是您需要先安装这些软件包。

答案 5 :(得分:0)

由于您的请求中发送了多个响应。如果在其他条件下使用返回关键字,则代码将正常运行

if (!profile) {
    return res.status(404).json({ error: "No Profile Found" });
}
else {
    **return** res.json(profile);
}

答案 6 :(得分:0)

有一个针对节点错误[ERR_HTTP_HEADERS_SET]的简单修复。您需要在响应前添加return语句,以确保路由器在出错时正确退出:

router.post("/", async (req, res) => {
    
    let user = await User.findOne({email: req.body.email});   
    if (!user) **return** res.status(400).send("Wrong user");
    
});

答案 7 :(得分:0)

使用 ctrl + F 热键并找到所有“res”。关键词 然后用'return'前缀替换它们,

change  all 'res.' to  'return res.'

像这样:

res.send() 改为 --> 返回 res.send()

也许你有“res”。在某些块中,例如 if() 语句