Reputation: 9557
Say I have this code using the Router() of express.
authRoute.param('token', function(req, res, next, token) {
User.findOne({ 'local.resetPasswordToken': req.params.token, resetPasswordExpires: { $gt: Date.now() }}, function(err, user) {
if (!user) {
req.flash('error', 'error msg here');
return res.redirect('/forgot');
}
req.user = user;
})
next();
})
authRoute.route('/reset/:token')
.get(function(req, res) {
res.render('reset', {
user: req.user
})
})
I get this error:
_http_outgoing.js:346
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
Without the Router(), this is how it looks:
app.get('/reset/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('/forgot');
}
res.render('reset', {
user: req.user
});
});
});
What am I doing wrong with the Router.param side? I read on the error message given, and I learn it happens when an attempt is made to set headers on response that's already been set.
Upvotes: 0
Views: 115
Reputation: 2214
You're calling next()
in authRout.param immediately, thus allowing other middleware's to, at some point, end up calling res.end()
(res.render, res.send, etc) before the Mongoose callback has been invoked. My assumption is you're getting this error when allowing middleware's execute (previously explained) then invoking res.redirect('/forgot')
after one of the middlewares has already "ended" the response.
The solution is to wait for your db response before continuing down the middleware chain, simply an async issue. Consider the folllowing:
authRoute.param('token', function(req, res, next, token) {
User.findOne({ 'local.resetPasswordToken': req.params.token, resetPasswordExpires: { $gt: Date.now() }}, function(err, user) {
// pass error to middlewares
if (err) return next(err)
// Stop the middleware chain i.e. return res.redirect
if (!user) {
req.flash('error', 'error msg here');
return res.redirect('/forgot');
}
req.user = user;
// important! call `next()` after mongo response
next()
})
})
This isn't happening in the single request handler (your latter example) because you're properly handling async - not ending the http response before the Mongoose callback is invoked.
Upvotes: 2