Error: Can't set headers after they are sent to the client
The res
object in Express is a subclass of Node.js's http.ServerResponse
(read the http.js source). You are allowed to call res.setHeader(name, value)
as often as you want until you call res.writeHead(statusCode)
. After writeHead
, the headers are baked in and you can only call res.write(data)
, and finally res.end(data)
.
The error "Error: Can't set headers after they are sent." means that you're already in the Body or Finished state, but some function tried to set a header or statusCode. When you see this error, try to look for anything that tries to send a header after some of the body has already been written. For example, look for callbacks that are accidentally called twice, or any error that happens after the body is sent.
In your case, you called res.redirect()
, which caused the response to become Finished. Then your code threw an error (res.req
is null
). and since the error happened within your actual function(req, res, next)
(not within a callback), Connect was able to catch it and then tried to send a 500 error page. But since the headers were already sent, Node.js's setHeader
threw the error that you saw.
Comprehensive list of Node.js/Express response methods and when they must be called:
Response must be in Head and remains in Head:
res.writeContinue()
res.statusCode = 404
res.setHeader(name, value)
res.getHeader(name)
res.removeHeader(name)
res.header(key[, val])
(Express only)res.charset = 'utf-8'
(Express only; only affects Express-specific methods)res.contentType(type)
(Express only)
Response must be in Head and becomes Body:
res.writeHead(statusCode, [reasonPhrase], [headers])
Response can be in either Head/Body and remains in Body:
res.write(chunk, encoding='utf8')
Response can be in either Head/Body and becomes Finished:
res.end([data], [encoding])
Response can be in either Head/Body and remains in its current state:
res.addTrailers(headers)
Response must be in Head and becomes Finished:
return next([err])
(Connect/Express only)- Any exceptions within middleware
function(req, res, next)
(Connect/Express only) res.send(body|status[, headers|status[, status]])
(Express only)res.attachment(filename)
(Express only)res.sendfile(path[, options[, callback]])
(Express only)res.json(obj[, headers|status[, status]])
(Express only)res.redirect(url[, status])
(Express only)res.cookie(name, val[, options])
(Express only)res.clearCookie(name[, options])
(Express only)res.render(view[, options[, fn]])
(Express only)res.partial(view[, options])
(Express only)
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client - Ayuda no se porque sucede eso
after if-else block, you again try to send response.By putting return
after sending response in each block, you can fix your problem or other simple way, just comment res.send("recibido")
.
simple way is to just comment res.send("recibido")
you can write your code this way:
router.post('/', (req, res) => {
const {titulo, director, year, rating} = req.body;
if (titulo && director && year && rating) {
const id = movies.length + 1;
const newMovie = {...req.body, id};
movies.push(newMovie);
res.json(movies);
} else {
res.status(500).json({error: 'Ha Ocurrido un error'});
}
// res.send('recibido');
});
module.exports = router;
Can't set headers after they are sent to the client [ERR_HTTP_HEADERS_SENT]
This error comes from attempting to send more than one response to the same http request.
You have res.send(find[i].result[j]);
inside a for
loop and you do not stop the inner loop after sending a response.
Thus, this code is capable of attempting to send multiple responses to the same request which you cannot do.
It's unclear from the code exactly what the desired solution is. If you only want to send the first response, then you can close the db and return
after you send a response which will terminate both for
loops.
If you intend to send multiple pieces of data, then accumulate the data you want to send in an array and send all the data once after all the loops are done.
If you're trying to send an array of all matching results, you can do this:
app.post('/', (req, res) => {
print(req, res)
})
function print(req, res) {
MongoClient.connect(url, function(err, db) {
if (err) {
console.log(err);
res.sendStatus(500);
return;
}
var dbo = db.db("cryptoDb");
dbo.collection("coinTable").find({}).toArray(function(err, find) {
if (err) {
console.log(err);
res.sendStatus(500);
db.close();
return;
}
const id = Capitalize(req.body.coinName);
const idUpper = id.toUpperCase();
const results = [];
for (let findItem of find) {
for (let j = 0; j < 100; j++) {
if (findItem.result[j].name == id || findItem.result[j].symbol == idUpper) {
results.push(findItem.result[j]);
}
}
}
res.send(results);
if (!results.length) {
console.log("No results");
}
db.close();
});
});
function Capitalize(s) {
return s[0].toUpperCase() + s.slice(1).toLowerCase();
}
}
Other Notes:
I changed the
if (err) { ... }
handling on your database call to actually send an error response. All paths through your request handler need to send a response or cause a response to be sent.The hard coded loop from 0 to 99 is a bit odd as you don't check if the
.result
array actually has that many entries in it. That could result in a run-time error if the data isn't exactly how you are expecting it.You don't have any validation of the
req.body
data you are expecting. All data arriving from the user should be validated before assuming it is what you are expecting.
How to fix the cannot set headers after they are sent to the client error in node?
In your authenticate
functions, you forgot to add an else
statement to if (mycookie)
.
Unauthorized will therefore always be sent, which is clearly the reason why you get unauthorized with a good cookie, and then as unauthorized as already been sent, the error you describe will be throw when getUser tries to sent the http response.
Wrap return res.sendStatus(401);
in an else
statement and it should work fine.
Error [ERR_HTTP_HEADERS_SENT] Cannot set headers after they are sent to the client
you need to return your error response once an error occurred or otherwise your function will keep running and executing the below code even after the error.
'/add/grade',
[
check('name', 'grade name is require')
.not()
.isEmpty()
],
auth,
admin,
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) return res.status(400).send({ errors: errors.array() });
const grade = new Grade(req.body);
grade.save((err, doc) => {
if (err) return res.status(400).send({ success: false, err });
return res.status(200).send({
success: true,
grade: doc,
msg: 'Grade add successfully'
});
});
}
);
because if an error occurs or any validation is failed the API sends the response but is not returned so the function keeps on going and executes all other code below it.
As you should know that in an HTTP request response can only be sent once and when the function again sends the response after an error it shows you that cannot send response headers after they are sent to the client.
Hope this helps. GOOD LUCK :)
How do you solve the Cannot set headers after they are sent to the client error in node js?
There are two ways of using promises. Either you use the then
/catch
callbacks or you can use async
/await
to allow you to write them synchronously.
then/catch method
// Some code before promise
somePromise.then(() => {
// Some code after promise action is successful
}).catch(err => {
// Some code if promise action failed
})
// Some code after promise definition you think should run after the above code
// THIS IS WHAT IS HAPPENING WITH YOUR CODE
async/await method
// Some code before promise
await somePromise;
// Some code after promise action is successful
The latter approach was introduces to avoid the callback hell problem and it seems that's where your error is arising from.
When using callback callbacks you must make sure that nothing is defined after the promise definition else it will run before the promise resolves (Which is counter-intuitive since placing code B after code B should make A run before B)
Your error is because your callbacks are probably running AFTER the response has been sent and express does not allow you to send multiple responses for a request.
You should make sure that where ever res.send
or res.json
is being called exist within the callback.
This article should help you understand promises much better...
Hope this helps...
Related Topics
Why Does a Regexp With Global Flag Give Wrong Results
How to Get the Difference Between Two Arrays in JavaScript
Share Data Between Angularjs Controllers
How to Split a String, Breaking At a Particular Character
React Setstate Not Updating State
Insert HTML into View from Angularjs Controller
Explain the Encapsulated Anonymous Function Syntax
How to Force Js to Do Math Instead of Putting Two Strings Together
Refresh Image With a New One At the Same Url
Convert Js Object to Json String
Parsing a String to a Date in JavaScript
Use Dynamic Variable Names in JavaScript
JavaScript by Reference Vs. by Value
Why Is the Method Executed Immediately When I Use Settimeout
How to Completely Uninstall Node.Js, and Reinstall from Beginning (Mac Os X)
What Is a Good Regular Expression to Match a Url
How to Get the Caret Column (Not Pixels) Position in a Textarea, in Characters, from the Start
JavaScript Get Clipboard Data on Paste Event (Cross Browser)