Home > front end >  Node is crushing after post request
Node is crushing after post request

Time:12-01

I have the following index.js file:

var express = require('express');
const { body, validationResult } = require('express-validator');
var router = express.Router();
const bcrypt = require('bcryptjs');
const User = require('../models/user');

router.get('/', function(req, res, next) {
  res.render('index', { title: 'Messages' });
});
router.get('/sign-up', function(req, res, next) {
  res.render('sign-up', {title: 'sign up'})
});
router.post(
  '/sign-up', 
  body('username', 'Username is required').trim().isLength({min:1}).escape(), 
  body('password', 'Password is required').trim().isLength({min:1}).escape(),
  body('confPassword').custom((value, { req }) => {
    if (value !== req.body.password) {
      throw new Error('Password confirmation does not match password');
    }
    return true;
  }),
  (req, res, next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.render('sign-up', {title: 'Sign-up', errors: errors.errors})
    }
    User.find({ 'username': req.body.username}).exec(function(err, existingUser){
      if (err) {
        return next(err)
      }
      if (existingUser) {
        console.log(req.body.username)
        console.log(existingUser)
        res.render('sign-up', {title: 'Sign-up', error: ` ${req.body.username} already exists in the system. Please choose another username`})
      }
    })
    bcrypt.hash(req.body.password, 10, (err, hashedPassword) => {
      if (err) {
        return next(err)
      }
      const user = new User({
        username: req.body.username,
        password: hashedPassword
      }).save(err=> {
        if (err) {
          return next(err);
        }
        res.redirect("/")
      })
    })  
  }
)
router.get('/sign-in', function(req, res, next) {
  res.render('sign-in', {})
})

module.exports = router;

looking at the POST from /sign-up -- When I enter a username and matching passwords - the user is saved in MongoDB and no errors.

But if my passwords are not filled up or not matching or user exists in mongoDB the app is crushing and still creates a user and saves it into MongoDB.

This is the error I get:

node:events:504
  throw er; // Unhandled 'error' event
  ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:371:5)

at ServerResponse.setHeader (node:_http_outgoing:576:11)

at ServerResponse.header (/Users/adi/programming/learning/myProjects/members-only/node_modules/express/lib/response.js:767:10)

at ServerResponse.location (/Users/adi/programming/learning/myProjects/members-only/node_modules/express/lib/response.js:884:15)

at ServerResponse.redirect (/Users/adi/programming/learning/myProjects/members-only/node_modules/express/lib/response.js:922:18)

at /Users/adi/programming/learning/myProjects/members-only/routes/index.js:51:13

at /Users/adi/programming/learning/myProjects/members-only/node_modules/mongoose/lib/model.js:5207:18

at processTicksAndRejections (node:internal/process/task_queues:78:11)

Emitted 'error' event on Function instance at:

at /Users/adi/programming/learning/myProjects/members-only/node_modules/mongoose/lib/model.js:5209:15

at processTicksAndRejections (node:internal/process/task_queues:78:11) {
code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...

CodePudding user response:

Your post handler needs to be something like

router.post(
  "/sign-up",
  body("username", "Username is required").trim().isLength({ min: 1 }).escape(),
  body("password", "Password is required").trim().isLength({ min: 1 }).escape(),
  body("confPassword").custom((value, { req }) => {
    if (value !== req.body.password) {
      throw new Error("Password confirmation does not match password");
    }
    return true;
  }),
  (req, res, next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.render("sign-up", { title: "Sign-up", errors: errors.errors });
      return;
    }
    User.find({ username: req.body.username }).exec((err, existingUser) => {
      if (err) {
        return next(err);
      }
      if (existingUser) {
        console.log(req.body.username);
        console.log(existingUser);
        res.render("sign-up", {
          title: "Sign-up",
          error: ` ${req.body.username} already exists in the system. Please choose another username`,
        });
        return;
      }
      bcrypt.hash(req.body.password, 10, (err, hashedPassword) => {
        if (err) {
          return next(err);
        }
        new User({
          username: req.body.username,
          password: hashedPassword,
        }).save((err) => {
          if (err) {
            return next(err);
          }
          res.redirect("/");
        });
      });
    });
  },
);

so

  • things are properly nested in the callbacks (only attempting to hash the password and creating the new user after verifying there is no existing user, etc.)
  • and that each res.render is followed by a return, so there's only one attempt at rendering the result.

As I mentioned in the comment, look into using async/await instead of callbacks for much simpler code.

  • Related