Node/Express - Can't set headers after they are sent - node.js

I have been dealing with this problem now for quite a while, and I can't seem to figure out why it's happening.
I'm getting the Error: Can't set headers after they are sent.
I was able to track down the offending Function Call via the Stack Trace, which leads me to believe that the error lies within this function:
exports.getCardUser = function(req, res, next) {
if (req.user) {
User.cardUser(req.user.userId, function(responseValue) {
res.json(200, responseValue);
});
} else {
res.send(401);
}
};
However, if I hit the Endpoint via a regular REST Client, iex: Hitting the API Endpoint in an Isolated Environment, the Error is not being thrown.
Any ideas?
Edit: skypjack's brought me on the right track - Callback was called twice. Thanks!

Related

Node / React Authentication API callback STUMPER

I've been developing for a year and change and this maybe a novice question but I've tried EVERYTHING (~150 hours worth of tries, YIKES) I will post my React Frontend and my Nodejs backend to hopefully get some clarity.
Key notes:
-I am using Auth0 authentication to build an api with a nodeJs server
-Auth0 says to use an https:// call which my localhost:3000 is not. However, everything about AUTH0 works except the API call invoked when a user logs in to redirect them and display their information on their profile. I have only found one solution to this which is a reverse proxy https:// server to make calls (I can stop here if this is the issue lol unless another easier method is out there). Also why would AUTH0 require production https servers to test???
-I have the correct CORS enabled on AUTH0's site and 99% sure NodeJs (I can get a console.log response from my API) and have tried many ways on the front end and backend
to solve.
Help would greatly, greatly, be appreciated.
Code:
function URLChecker() {
// setTimeout(function(){
// console.log("Executed immediately");
if (location.pathname.indexOf('/profile/') === 0) {
//setToken(true);
return true;
}
}
function tokenChanger() {
setToken(true);
console.log("Your token is presented as...", token)
}
useEffect(()=> {
//console.log("url checker is:" + URLChecker());
if(URLChecker() == true){
tokenChanger();
console.log(location)
if (token) {
console.log("token exists");
axios.defaults.headers.get['Access-Control-Allow-Origin'] = 'http://localhost:3000';
axios.get('http://localhost:8080/profile')
.then(res => {
//console.log(res);
console.log(res.data);
}).catch(error => {
console.log(error);
console.log("API for user FAILED")
})
}
app.get('/profile', requiresAuth(), (req, res, next ) => {
console.log(req.oidc.user);
res.header("Access-Control-Allow-Origin", "*");
res.redirect(http://localhost:3000/profile/${((req.oidc.user.nickname))})
});
(res(req.oidc.user) returns a localhost:8080/profile page that is blank with the JSON of the user's information displayed. My next step is to obviously make my frontend call a different API instead of /profile to hit an authentication required api that will return user data, however no matter what I've tried I always get stuck with the same error message. I am so close and don't know whether to stick with AUTH0 to solve this error or going with Google authentication which I hear is nice.
Thank you,
imgur link to error message on my frontend

NodejS : Error: Can't set headers after they are sent to the client

I am quite new to node and am currently encountering an error that seems pretty common: Error: Can't set headers after they are sent to the client.
I've read a few threads but cannot wrap my head around this one, here is my code so far:
router.get('/:id', (req, res) => User.findAll({
where : {
id: req.params.id,
},
attributes : {
exclude : ['updatedAt'],
}
})
.then(user => {
res.send(user);
res.sendStatus(200);
})
.catch((err) => console.log(err)));
What's wrong here? Any help and advices would be greatly appreciated!
The real reason behind this problem is that you are using both
res.send(user) and res.sendStatus(200).
The error says: Error: Can't set headers after they are sent to the client
You already send something to the client (in this case res.send(user)) and you can't send another thing now (in this case res.sendStatus(200)).
Once you do res.send, res.redirect, res.sendStatus, res.render, you should not do add any of these again.
You will get this problem if you are using more than one at the same time. Even if you have something like:
for(condition) {
res.send("1st");
}
res.send("2nd");
You should add return statements in front of them like:
for(condition) {
return res.send("1st");
}
return res.send("2nd");
Also as #Halil Akar said that 200 status is always returned with res.send. You can also use res.status(301).send(user) to send data and a status at the same time.
I hope it helps.

Handling request simltaneously in nodejs and passing it's response using only one res.send

I am developing an API which takes input in XML containing IDs for media and gives output in XMLform with details of given IDs. I am facing a problem while sending the response of second simultaneous request; here the second request goes into loop showing "loading" on postman.
What I am doing is calling a function in app.post which parses the media and gives output in the callback and send it using res.send, but it works only for single request.
While doing parallel request to same API either it goes in loop or it gives can't set the headers after they are sent as I am using res.send but res.send is the only way which I can use to send the response (even the next doesn't work).
var getCompositeData = function(req, res, next){
abc.getData(req.body, function(err, xmlOutput){
if(err){
console.log("error");
} else {
xmlData = xmlOutput
return next()
}
}
app.post(apiUrl, [
rawBodyParser({
type: 'application/xml'
}),
app.oauth.authorise()
], getCompositeData, function (req, res) {
res.setHeader('Content-Type', 'application/xml');
res.send(xmlData);
});
There are several issues with your code:
if (err) {
console.log("error");
}
If an error occurs, you still need to make sure a response will be sent back, otherwise the request will stall until a timeout happens. You can pass an error to next, and Express will handle it:
if (err) {
return next(err);
}
Next problem:
xmlData = xmlOutput
xmlData is an undeclared variable, which gets overwritten with each request. If two requests happens at (almost) the same time, it's likely that one client gets back an incorrect response (remember, Node.js runs JS code in a single thread; there is not thread-local storage so xmlData gets shared between all requests).
A good place to "store" this sort of data is in res.locals:
res.locals.xmlData = xmlOutput;
return next();
// and later:
res.send(res.locals.xmlData);

NodeJS Can't set headers error on res.redirect

At the end of an app.post function I am trying to redirect users to a different page (always ends up on the "massChangesSubmitted" page). I keep getting the error Error: Can't set headers after they are sent.when it hits the line return res.redirect('/mass_changes'). The SQL section of the code works great, the only thing that fails is the redirect.
I cannot for the life of me figure out why this is happening. Everything I can find online says the res.redirect line should work. Please help!
Post code
app.post('/massChangesSubmitted', function(req, res){
res.status(200).end();
massChangesSubmitted(function(err){});
return res.redirect('/mass_changes');
});
massChangesSubmitted code
function massChangesSubmitted(callback) {
var sql = 'UPDATE mass_changes SET submitted=1, submitted_datetime=now() WHERE submitted=0';
var dbh = mysql.createConnection(config.db["DB"])
dbh.query(sql, function(err, rows) {
if(err) {
callback(-1); // call callback with error.
} else {
callback(1); // call callback function without error.
console.log("Existing Mass Changes considered submitted")
};
dbh.end();
});
};
you have closed the connection when you called
res.status(200).end();
res.end() ends the connection so you would need to remove that. And also as mentioned in the comments res.status 200 might not be needed of its a res.redirect.
If you really need to send 200 then you can specify any valid https status code in redirect.
res.redirect(200, '/mass_changes');

Express Error Handling - Get Status Code

If I define error handling middleware with express like so:
app.use(function(err,req,res,next){
// Do Stuff
});
How do I get the HTTP status code of the error(or do I just assume is's a 500)?
Thanks,
Ari
In short, your code has to decide the appropriate error code based on the specific error you are handling within your error handling middleware.
There is not necessarily an HTTP status code generated at this point. By convention, when I call next(error) from a middleware function or router handler function, I put a code property so my error handling middleware can do res.status(err.code || 500).render('error_page', error); or something along those lines. But it's up to you whether you want to use this approach for your common 404 errors or only 5XX server errors or whatever. Very few things in express itself or most middleware will provide an http status code when passing an error to the next callback.
For a concrete example, let's say someone tried to register a user account in my app with an email address that I found already registered in the database, I might do return next(new AlreadyRegistered()); where the AlreadyRegistered constructor function would put a this.code = 409; //Conflict property on the error instance so the error handling middleware would send that 409 status code. (Whether it's better to use error handling middleware vs just dealing with this during the normal routing chain for this "normal operating conditions" error is arguable in terms of design, but hopefully this example is illustrative nonetheless).
FYI I also recommend the httperrors npm module which provides nicely-named wrapper classes with a statusCode property. I have used this to good effect in a few projects.
You could try to define the status code in the route:
app.get('/force-error', function(req, res) {
res.status(400)
next(new Error('Bad Request.'))
})
Then:
server.use(function serverErrorHandler (err, req, res, next) {
const code = res.statusCode
// if status 200 change to 500, otherwise get the defined status code
res.status(code === 200 ? 500 : code)
// check if it's a ajax request
if (req.xhr)
res.json({
error: {
status: res.statusCode,
message: err.message,
stack: err.stack,
}
})
else
next(err)
})

Resources