2
votes

I've been following a tutorial for a login/register authentication application. I keep getting the error "Can't set headers after they are sent" whenever I send POST requests. I tried to console.log the request body and it were empty. I don't know where I did wrong. Please help.

users.js

var express = require('express');
var router = express.Router();
var User = require('../models/User')

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

router.get('/register', function(req, res, next) {
  res.render('register', {title:'Register'});
});

router.get('/login', function(req, res, next) {
  res.render('login', {title: 'Login'})
});

router.post('/register', function(req, res, next) {
  var name = req.body.name;
  var email = req.body.email;
  var username = req.body.username;
  var password = req.body.password;
  var password2 = req.body.password2;

  if (req.files && req.files.profileimage) {
    console.log('Uploading file...');

    var profileimageOriginalName = req.files.profileimage.originalname;
    var profileimageName = req.files.profileimage.name;
    var profileimageMime = req.files.profileimage.mimetype;
    var profileimageExt = req.files.profileimage.extension;
    var profileimageSize = req.files.profileimage.size;
    var profileimagePath = req.files.profileimage.path;
  } else {
    var profileimageName = 'noimage.png'
  }

  req.checkBody('name', 'Name field is required').notEmpty();
  req.checkBody('email', 'Email field is required').notEmpty();
  req.checkBody('email', 'Email field is not valid').isEmail();
  req.checkBody('username', 'Username field is required').notEmpty();
  req.checkBody('password', 'Password field is required').notEmpty();
  req.checkBody('password2', 'Password does not match').equals(req.body.password);
  var errors = req.validationErrors()

  if (errors) {
    res.render('register', {
      errors: errors,
      name: name,
      email: email,
      username: username,
      password: password,
      password2: password2
    });
  } else {
    var newUser = new User({
      name: name,
      email: email,
      username: username,
      password: password,
      profileimage: profileimageName
     })
  }

  User.createUser(newUser, function(err, user) {
    if (err) throw err;
    console.log(user);
  })

  req.flash('sucess', 'You are now registered and may login');
  res.location('/');
  res.redirect('/');
})
module.exports = router;

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
var LocalStrategry = require('passport-local').strategy;
var bodyParser = require('body-parser');
var expressValidator = require('express-validator');
var flash = require('connect-flash');
var multer = require('multer')
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connection

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// handle file upload
var upload = multer({dest: './uploads'});

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


app.use(session({
  secret: 'secret',
  saveUninitialized: true,
  resave: true
}))

app.use(passport.initialize());
app.use(passport.session());

app.use(expressValidator({
  errorFormatter: function(param, msg, value) {
      var namespace = param.split('.')
      , root    = namespace.shift()
      , formParam = root;

    while(namespace.length) {
      formParam += '[' + namespace.shift() + ']';
    }
    return {
      param : formParam,
      msg   : msg,
      value : value
    };
  }
}));


app.use(flash())
app.use(function (req, res, next) {
  res.locals.messages = require('express-messages')(req, res);
  next();
});

app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

UPDATE: If I remove the validator codes, the error will be gone, but the post request body still empty

UPDATW 2: Error log

POST /users/register 500 26.552 ms - 2629
Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
    at ServerResponse.header (F:\Projects\nodeauth\node_modules\express\lib\response.js:718:10)
    at ServerResponse.send (F:\Projects\nodeauth\node_modules\express\lib\response.js:163:12)
    at done (F:\Projects\nodeauth\node_modules\express\lib\response.js:957:10)

    at Object.exports.renderFile (F:\Projects\nodeauth\node_modules\jade\lib\index.js:374:12)
    at View.exports.__express [as engine] (F:\Projects\nodeauth\node_modules\jade\lib\index.js:417:11)
    at View.render (F:\Projects\nodeauth\node_modules\express\lib\view.js:126:8)
    at tryRender (F:\Projects\nodeauth\node_modules\express\lib\application.js:639:10)
    at EventEmitter.render (F:\Projects\nodeauth\node_modules\express\lib\application.js:591:3)
    at ServerResponse.render (F:\Projects\nodeauth\node_modules\express\lib\response.js:961:7)
    at F:\Projects\nodeauth\app.js:99:7
    at Layer.handle_error (F:\Projects\nodeauth\node_modules\express\lib\router\layer.js:71:5)
    at trim_prefix (F:\Projects\nodeauth\node_modules\express\lib\router\index.js:310:13)
    at F:\Projects\nodeauth\node_modules\express\lib\router\index.js:280:7
    at Function.process_params (F:\Projects\nodeauth\node_modules\express\lib\router\index.js:330:12)
    at next (F:\Projects\nodeauth\node_modules\express\lib\router\index.js:271:10)
    at Layer.handle_error (F:\Projects\nodeauth\node_modules\express\lib\router\layer.js:67:12)
    at trim_prefix (F:\Projects\nodeauth\node_modules\express\lib\router\index.js:310:13)
    at F:\Projects\nodeauth\node_modules\express\lib\router\index.js:280:7
    at Function.process_params (F:\Projects\nodeauth\node_modules\express\lib\router\index.js:330:12)
    at Immediate.next (F:\Projects\nodeauth\node_modules\express\lib\router\index.js:271:10)
    at Immediate.<anonymous> (F:\Projects\nodeauth\node_modules\express\lib\router\index.js:618:15)
2
where is your app.js and you have used body-parser to receive application/x-www-form-urlencoded?Vikash Kumar
@VickyR I updated the OP with app.js, and I'm using enctype='multipart/form-data' for the formRyan Aleksander
post the index.js of routes directoryavck
@user3354205, First of all remove res.location('/') from users.js and handle files thourgh multer in post.Vikash Kumar
@avck It's almost indentical to the default one, I only changed the titleRyan Aleksander

2 Answers

1
votes

You can not set the header after it has been sent to client.

res.render sends the sends the response when there is error. After that again you are trying to send the headers via res.location and res.redirect.

Move the res.redirect to the else block.

  var multer = require('multer');
  var upload = multer(); 
  router.post('/register', upload.array(), function(req, res, next) {
  var name = req.body.name;
  var email = req.body.email;
  .................. 
  if (errors) {
    res.render('register', {
     errors: errors,
     name: name,
     email: email,
     username: username,
     password: password,
     password2: password2
  });
  } else {
   var newUser = new User({
    name: name,
    email: email,
    username: username,
    password: password,
    profileimage: profileimageName
   })
  //now this is also in the else block
   User.createUser(newUser, function(err, user) {
    if (err) throw err;
    console.log(user);
  })

  req.flash('sucess', 'You are now registered and may login');
  res.location('/');
  res.redirect('/');
  //till here so you don't send response twice
}


})
0
votes

You are facing this because of :

req.flash('sucess', 'You are now registered and may login'); //this is okay
res.location('/'); //[1]
res.redirect('/'); //[2]

[1] you are setting headers and redirecting to '/' route.

[2] you are setting headers passing status code: 302 and redirecting to '/' route.

oh wait? didn't you already set headers in step 1? Yes that's what the error means. You can have only one response per request. Use this for more info.