Node Js Cannot set headers after they are sent to the client - node.js

Hello StackOverFlow Army,
im getting
Cannot set headers after they are sent to the client
Error in this code.
getUserInfo: async (req, res) => {
try {
const { id } = req.user;
// Check is User Data present in Redis
redis_client.GET("USER_" + id, (err, user) => {
if (err) {
console.log(err.message);
return res.status(500).json({ msg: "Server Error!" });
}
// If present Return User data
// Return User data
user = JSON.parse(user);
if (user) return res.json({ user });
});
// Else Fetch Data from Database
const user = await Users.findById(id).select("-password");
// Set to Redis
redis_client.SET(
"USER_" + id.toString(),
JSON.stringify(user),
"EX",
10,
(err, reply) => {
if (err) {
console.log(err.message);
return res.status(500).json({ msg: "Server Error!" });
}
}
);
// Return User data
res.json({ user });
} catch (error) {
return res.status(500).json({ msg: error.message }); // Line 77
}
},
Error On Line 77.
Please Help me, i cannot see why it is happening. Im sending response and there is no collision between sending response. Is it a good practice to store a user data in redis for faster fetching.
The Expiry time is very low like 10s so if user spam refresh it will help to fetch faster. Any suggestions is appreciated.

You need to put your else part inside the callback function of redis_client.GET , just below this line
**if (user) return res.json({ user });
what happens now is, if this above if condition goes true , then also the the code will move to the next line as return statement will just return from the callback function and not end the response cycle.

Related

Cannot set headers after they are sent to the client using express-session

const emailaddress = req.body.emailaddress;
const password = req.body.password;
if (emailaddress && password) {
const query = `SELECT * FROM users where email=? AND password=?`;
connection.query(
query,
[emailaddress, password],
function (err, results, fields) {
if (err) {
res.send({
code: 500,
failed: "Error ocurred",
});
}
if (results.length > 0) {
req.session.regenerate(function (err) {
// if (err) next(err);
req.session.loggedin = true;
req.session.emailaddress = req.body.emailaddress;
req.session.save(function (err) {
// if (err) return next(err);
res.redirect("/home");
});
});
} else {
res.send("Incorrect email address and/or password!");
}
res.end();
}
);
} else {
res.send("Please enter username and/or password");
res.end();
}
I tried using the above code using express-session to store session values. but it gives the following error.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How can I avoid this. I already tried many solutions. I am following their documentation. Please help. Thank you.
https://www.npmjs.com/package/express-session
Possible problems:
Else block calls send and last line outside if and else calls end().
So if it falls into the Else block, both send and end will be called causing that error.
You also have multiple call to next(err), without knowing that is the next handler, I can tell you for sure, but they might be calling send as well. Which would fall into the same scenario as above.
I see you made some changes in your code after my answer.
Let me try again, you cannot use res.send and res.end together, you need to pick one. Also you need to make sure you are only calling res.send once.
your code should be something like this:
const emailaddress = req.body.emailaddress;
const password = req.body.password;
if (emailaddress && password) {
const query = `SELECT * FROM users where email=? AND password=?`;
connection.query(
query,
[emailaddress, password],
function (err, results, fields) {
if (err) {
res.send({
code: 500,
failed: "Error occurred",
});
return; // make sure your function execution stops here, as you already called send();
}
if (results.length > 0) {
req.session.regenerate(function (err) {
// if (err) next(err);
req.session.loggedin = true;
req.session.emailaddress = req.body.emailaddress;
req.session.save(function (err) {
// if (err) return next(err);
res.redirect("/home");
});
});
} else {
res.send("Incorrect email address and/or password!");
return; // same thing, called send() make sure to end the function
}
// res.end(); you probably don't need this
}
);
} else {
res.send("Please enter username and/or password");
// res.end(); you probably don't need this
return;
}

Cannot set headers after they are sent to the client erro when i ask the same route for 2nd time? (Always)

I am now trying to write a update function in mongoose.
My code is like this
app.patch("/users/:id", async (req, res) => {
let _id = req.params.id;
if (_id.match(/^[0-9a-fA-F]{24}$/)) {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, {
new: true,
runValidators: true,
});
if (!user) {
return res.status(404).send("User not found");
}
res.send(user);
} catch (err) {
res.status(400).send(err);
}
}
res.send("error format");
});
As you can see i am using path method to update the obj.
The problem is on this line
if (_id.match(/^[0-9a-fA-F]{24}$/)) {
When ever i try to match the object id, On the 2nd calls I always get this error. Can Someone explain why?
Cannot set headers after they are sent to the client
If I remove this if statement the error goes away.
You forgot to exit from a handler after res.send(user).
if (!user) {
return res.status(404).send("User not found");
}
res.send(user);
return;
Without return your code continues to execute and next line will be res.send("error format");

Error: Function returned undefined, expected Promise or value

I setup a pubsub function with firebase functions to do some operations every so often in the Firestore. In order to do this I need to make a request to a third party API to get the updated data and then I want to insert that data into the correct collection and document in the Firestore.
const request_promise = require('request-promise')
exports.scheduledFunction = functions.pubsub.schedule('every 2 minutes').onRun((context) => {
console.log('This will be called every 2 minutes')
var username = ''
var password = ''
var options = {
url: 'path.to.api.com',
auth: {
user: username,
password: password
},
json: true
}
request_promise(options)
.then(function (product) {
console.log(product.product_id)
db.collection('products').doc(product.product_id).set(product)
.then(() => {
console.log('Document successfully written')
})
.catch(error => {
console.log('Error writing product to firestore', error)
})
})
.catch(function (err) {
console.log('Failed to get product', error)
})
});
In the code above if I comment out the call to add the data to the Firestore I the correct product_id prints to the console, so I know the request is working but with it left in I get 'Function returned undefined, expected Promise or value'.
You're not returning anything at your execution. A console.log isn't treated as a return
request_promise(options)
.then(function (product) {
console.log(product.product_id)
// add an implicit return here
return db.collection('products').doc(product.product_id).set(product)
.then(() => {
console.log('Document successfully written')
// need's to return something here, using a boolean for simplicity
return true;
})
.catch(error => {
console.log('Error writing product to firestore', error)
// throw will exit the function call
throw Error('Error writing product to firestore', error);
})
})
.catch(function (err) {
console.log('Failed to get product', error);
// throw will exit the function call
throw Error('Failed to get product', error);
})
With proper promise chaining , this looks more clean
rp(options)
.then((product) =>
{
console.log(product.product_id)
// add an implicit return here
return db.collection('products').doc(product.product_id).set(product)
})
.then(() =>
{
console.log('Document successfully written')
// need's to return something here, using a boolean for simplicity
return true;
})
.catch(function (err)
{
console.log('Failed to get product', error);
// throw will exit the function call
throw Error('Failed to get product', error);
});
Also it is not recommended to throw the errors from catch block, catch block are meant to catch errors and handle them and not to throw errors. There are few bits in your code you need to improve but this is not part of this question
Cheers,
Happy Coding

Node/Express: Cannot set headers after they are sent to the client

I have the below code where I am trying to validate a user with its credentials from Mongo DB :
{
validate: async function (email, password, res) {
console.log('Inside validate method');
try {
var dbUserObj = await User.findOne({ email: email }, (err, user) => {
console.log('Inside validate method111111');
if (err) {
return res.status(500).send('Error on the server.');
}
console.log('Inside validate method 22222');
if (!user) {
return res.status(404).send('No user found.');
}
console.log('Inside validate method33333');
var passwordIsValid = bcrypt.compareSync(password, user.password);
console.log('Is Valid Password :: ' + passwordIsValid);
if (!passwordIsValid) {
return res.status(401).send({
auth: false,
token: null
});
}
});
} catch (e) {
}
console.log('DDDDBBBB USSSERRRR :::' + dbUserObj);
return dbUserObj;
}
}
The below code calls the validate method :
var auth = {
login: function(req, res,next) {
console.log('Inside login');
var email = req.body.email || '';
var password=req.body.password || '';
console.log('Before validate user');
// Fire a query to your DB and check if the credentials are valid
var dbUserObj = auth.validate(email,password,res);
if (!dbUserObj) { // If authentication fails, we send a 401 back
res.status(401);
res.json({
"status": 401,
"message": "Invalid credentials"
});
return;
}
if (dbUserObj) {
res.send(genToken(dbUserObj));
}
}
Whenever there is a condition when the password is incorrect i am getting the error :
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Cannot really figure out the issue.
The route that calls your validate() needs to accept the next callback parameter from express, otherwise the framework assumes that when the asynchronous function returns (which occurs at the first await expression), it has completed all its work and at that point it continues down its routes to the default error handling which sends a 404 before your database query resumes async control flow in validate.
When your route handler accepts the next parameter, it indicates to express that the route will handle asynchronously, and you can do 1 of 3 things:
Don't call next() if you already send a response (which you always do in this case).
Call next() with no arguments if you don't send a response and want to delegate the response handling to the remaining routes.
Call next(error) if you want to delegate the response handling to remaining middleware which will handle the error reporting and response for you.

NodeJS, Is it a bad practise to return res.json

I'm building a ExpressJS application with NodeJS. My question is there any performance difference if I do
app.get('/test', function(req, res) {
fn(function(err, data) {
if (err) {
return res.json(400, {
error: 1,
msg: "some error"
});
}
///more code
});
});
instead of
app.get('/test', function(req, res) {
fn(function(err, data) {
if (err) {
res.json(400, {
error: 1,
msg: "some error"
});
return;
}
///more code
});
});
Do returning the res variable make any addition load on the server. Both codes work, just the first looks better to me and I save 1 line.
On the contrary, I think many would tell you this sort of idiom is a very sound practice as it makes clear to the reader (often your future self) that you are exiting). What is very nice about the strategy in this particular case is that you can save a bit more code since you now only have a single statement in your conditional branch, which means you can lose some curly braces.
app.get('/test', function(req, res) {
fn(function(err, data) {
if (err) return res.json(400, {
error: 1,
msg: "some error"
});
///more code
});
});
But you asked if there was a performance difference. If there is, I think it would be all but imperceptible.
Returning an object in a function don't make additional load.
On your exemple, based on callback function, there is no difference.
But what if app.get return a Promise ?
This code will provide an Unhandled rejection Error
app.get('/test')
.then( (data) =>
{ /* do something with your data that can throw a functional error
for exemple request for a user on your database based on your data */
if (!user) res.json(401, {msg: 'USER NOT FOUND'});
if (user.someProperty) //will throw an error when user is not found
res.json(200, {msg: 'USER DID IT'});
})
.catch( (err) => {
res.json(500, {msg: 'OUTCH'});
throw(err);
});
This code will not
app.get('/test')
.then( (data) =>
{ /* do something with your data that can throw a functional error
for exemple request for a user on your database based on your data */
if (!user) return res.json(401, {msg: 'USER NOT FOUND'});
if (user.someProperty) //will not be evaluate when user is not found
return res.json(200, {msg: 'USER DID IT'});
})
.catch( (err) => {
res.json(500, {msg: 'OUTCH'});
throw(err);
});
When using promise always return ;)

Resources