Reputation: 141
I ran into a problem while implementing a registration system that uses tokens in order to prevent random users from creating multiple accounts.
The code runs until the very end, responses work as expected, but I get a warning afterwards, that says: UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
It says the problem happens at line 44, which is a catch statement for the mongoose save method.
newRegistrationToken.save()
.then(newRegistrationToken => res.status(200).json(newRegistrationToken))
.catch(err => res.status(500).json(err));
I have been searching for the solution, the answer always was that a catch statement is missing, resulting in this warning. However, in my code, I don't see any missing catch statements, so I am a bit lost here.
Here is the whole route:
router.post('/create', (req, res) => {
const { errors, isValid } = validateRegistrationToken(req.body);
if(!isValid) return res.status(400).json(errors);
// Searching for an active token associated with the e-mail address given
console.log("search for active token");
ModelRegistrationToken.findOne({
email: req.body.email,
expiresAt: { $gte: Date.now() }
}).then(user => {
// if user found
if(user){
// check if the user is already registered
console.log("search for registered user");
ModelUser.findOne({email: user.email}).then((registered) => {
if(registered)
return res.status(400).json({email: 'There\'s a user already registered with the e-mail address given'});
return res.status(400).json({email: 'The address given already has an active registration token'});
}).catch(err => console.log(err));
}
// Otherwise create a new token
const newRegistrationToken = new ModelRegistrationToken({
email: req.body.email,
expiresAt: new Date(Date.now() + Number.parseInt(config.REG_TOKEN_EXPIRATION_PERIOD) * 24 * 60 * 60 * 1000)
});
console.log("save token");
newRegistrationToken.save()
.then(newRegistrationToken => res.status(200).json(newRegistrationToken))
.catch(err => res.status(500).json(err));
}).catch(err => res.status(500).json(err));
});
I can't seem to figure this out, so I would appreciate your help on this one..
Upvotes: 1
Views: 1143
Reputation: 370759
You have:
if (user) {
// do stuff and call res.json
}
// do other stuff and call res.json
If user
exists, res.json
will be called twice. Try returning at the bottom of the if (user)
block:
if (user) {
// check if the user is already registered
console.log("search for registered user");
ModelUser.findOne({
// ...
}).catch(err => console.log(err));
return; // <---------------------------------
}
// Otherwise create a new token
const newRegistrationToken = new ModelRegistrationToken({
email: req.body.email,
expiresAt: new Date(Date.now() + Number.parseInt(config.REG_TOKEN_EXPIRATION_PERIOD) * 24 * 60 * 60 * 1000)
});
// ...
I'd also recommend sending status 500 if the inner findOne
happens to error, else the response will hang: turn
}).catch(err => console.log(err));
into something like
}).catch(err => res.status(500).json(err));
like you're doing elsewhere.
Upvotes: 1