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

在使用 Passport.js、 Express 和 Mongoose 时,我在 NodeJS 中遇到了这个奇怪的问题。基本上,我得到一个错误说“不能设置标题后,他们被发送到客户端”,即使我没有发送一个以上的标题。

我读过其他的帖子,也试用过,但没有一个奏效。

我仔细研究了 Github 的问题,似乎找不到解决办法。我得到的问题是,当我发送多个响应标头时会触发此错误,但事实是,我没有发送多个标头。感觉怪怪的。

这是我的堆栈跟踪:

(节点: 9236) DerecationPolice: 当前 URL 字符串解析器已被弃用,将在将来的版本中删除。若要使用新的解析器,请将选项{ useNewUrlParser: true }传递给 MongoClient.connect。

在端口5000上运行的服务器
MongoDB 连接错误
[ ERR _ HTTP _ HEADERS _ SENT ] : 在将标头发送到 客户
在 validateHeader (_ http _ out. js: 503:11)
在 ServerResponse.setHeader (_ http _ out. js: 510:3)
在 ServerResponse.header (/Users/lourdesroashan/code/github/devlog/node _ module/Express/lib/response. js: 767:10)
在 ServerResponse.json (/Users/lourdesroashan/code/github/devlog/node _ module/Express/lib/response. js: 264:10)
在 Profile.findOne.then.profile (/Users/lourdesroashan/code/github/devlog/ways/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 中,当试图获得认证用户时,出现了一个问题。我忘了在“ done”方法上使用“ return”,这导致了这个问题。刚刚添加了返回语句,它工作了!

212523 次浏览

That particular error occurs whenever you try to send more than one response to the same request and is usually caused by improper asynchronous code.

The code you show in your question does not appear like it would cause that error, but I do see code in a different route here that would cause that error.

Where you have this:

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

You need to change it to:

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

You don't want the code to continue after you've done res.status(404).json({ errors }); because it will then try to send another response.


In addition, everywhere you have this:

if (err) throw err;

inside an async callback, you need to replace that with something that actually sends an error response such as:

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

throwing inside an async callback just goes back into the node.js event system and isn't thrown to anywhere that you can actually catch it. Further, it doesn't send a response to the http request. In otherwords, it doesn't really do what the server is supposed to do. So, do yourself a favor and never write that code in your server. When you get an error, send an error response.


Since it looks like you may be new here, I wanted to compliment you on including a link to your full source code at https://github.com/lourdesr/devlog because it's only by looking at that that I was able to see this place where the error is occuring.

Sorry for the Late response, As per the mongoose documentation "Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. However, unlike promises, calling a query's .then() can execute the query multiple time"

so to use promises

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

Then

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

here is an nice article about switching out callbacks with promises in Mongoose

and this answer on mongooses promise rejection handling Mongoose right promise rejection handling

I was receiving this error because of a foolish mistake on my part. I need to be more careful when referencing my other working code. The truly embarrassing part is how long I spent trying to figure out the cause of the error. Ouf!

Bad:

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

Good:

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

I got the same error using express and mongoose with HBS template engine. I went to Expressjs and read the docs for res.render, and it says // if a callback is specified, the rendered HTML string has to be sent explicitly. So I wasnt originally sending my html explicitly in the callback,. This is only for a contact form btw, not login info, albeit GET

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

you have to enable Promises in your programm, in my case i enabled it in my mongoose schema by using mongoose.Promise = global.Promise . This enables using native js promises.

other alternatives to this soloution is :

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

and

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

but you need to install these packages first.

Because of multiple response sending in your request. if you use return key word in your else condition your code will run properly

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

There is a simple fix for the node error [ERR_HTTP_HEADERS_SET]. You need to add a return statement in front of your responses to make sure your router exits correctly on error:

router.post("/", async (req, res) => {
    

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

});

Use ctrl + F hotkey and find all 'res.' keywords then replace them with 'return res.',

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

something like this:

res.send() change to --> return res.send()

maybe you have 'res.' in some block, like if() statement

My problem besides not returning, i was forgetting to await an asynchronous function in the handler. So handler was returning and after a bit the async function did its thing. 🤦🏻‍♀️

Before:

req.session.set('x', {...});
req.session.save();
return req.status(200).end();

When i needed to await:

req.session.set('x', {...});
await req.session.save();
return req.status(200).end();

In react, if your are calling the function in useEffect hook, make sure to add a dependency to the dependency Array.

I had this error from an if statement not having an else block.

if(someCondition) {
await () => { }


}


await () => { }


I changed the above to this below and solved my issue

if(someCondition) {
await () => { }


} else {
await () => { }
}




This also happen when you tries to send the multiple response for a same request !! So make sure you always use return keyword to send response to client inorder to stop the further processing !!

Where you have this:

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

You need to change it to:

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

For me, I accidentally put a res.status inside of a for loop. So my server would trigger the error the second time a res.status was returned. I needed to put the res.status outside of the for loop so it would only trigger once within the function.

  1. First of all : make sure you didn't miss any asynchronous action without an async/await or use promises/callbacks.
  2. Then attach any res with the return keyword : return res.status(..).json({});
  3. And finally which was my problem: don't use return res.sendStatus if you always have some return res... inside a callback function, but you can always do a retun res.status();
    in my case it was :
    users.save((err,savedDoc){
    if(err) return res.status(501).json({})
    res.status(200).json({});
    });
    return res.status(500); // instead ofdoing return res.sendStatus(500)

I'm putting this here for anyone else who has the same problem as me- this happened to me because I'm using the next() function without a return preceding it. Just like a lot of the other answers state, not using return with your response will / can cause / allow other code in the function to execute. In my case, I had this:

app.get("/customerDetails", async (req, res, next) => {


//  check that our custom header from the app is present
if (req.get('App-Source') !== 'A Customer Header') next();


var customerID = req.query.CustomerID


var rows = await get_customer_details(customerID);


return res.json(rows);
});

In my case, I forgot to include the header in my request, so the conditional statement failed and next() was called. Another middleware function must have then been executed. After the middleware finishes, without a return, the rest of the code in the original middleware function is then executed. So I simply added a return before my next() call:

//  serve customer details payload
app.get("/customerDetails", async (req, res, next) => {


//  check that our custom header from the app is present
if (req.get('App-Source') !== 'A Customer Header') return next();


var customerID = req.query.CustomerID


var rows = await get_customer_details(customerID);


return res.json(rows);
});