Home > database >  Cannot set headers after they are sent to the client Nodejs and Angular
Cannot set headers after they are sent to the client Nodejs and Angular

Time:03-14

I am developing login and register services with Nodejs Express. Every request in postman I get same error:

enter image description here

Funny thing is that I get response in postman (register, login i even receive my JWT token but every time after request I can't do anything without restarting the service in my terminal)

My index.ts

 import express from "express";
 const https = require("https");
 import cors from "cors";
 import mongoose from "mongoose";
 const app = express();

 //import routes
 const usersRoute = require("./routes/users");

 //Middleware
 app.use(cors());
 app.use(express.urlencoded({ extended: false }));
 app.use(express.json());

 //route midddlewares
 app.use("/api/users", usersRoute);

 //connect to db
 mongoose
   .connect("mongodb://localhost:27017/loginregister")
   .then(() => {
     console.log("connected to database");
   })
   .catch(() => {
     console.log("connection failed!");
   });
 const PORT = 3000;
 app.listen(PORT, () => console.log(`Server up and running on port ${PORT}`));

And my users.ts

 import express from "express";
 const router = express.Router();
 const User = require("../models/User");

 const {
   registerValidation,
   loginValidation,
 } = require("../middleware/validation");
 const bcrypt = require("bcryptjs");
 const jwt = require("jsonwebtoken");
 const secretKey = "f43g34gergeerg";
 const verifyToken = require("../middleware/verifyToken");

 //REGISTER user
 router.post("/register", async (req, res) => {
   //VALIDATE DATA from Joi, before register
   const { error } = registerValidation(req.body);
   if (error) return res.status(400).send(error.details[0].message);

   //check if user is alredy in database
   const emailExist = await User.findOne({ email: req.body.email });
   if (emailExist) return res.status(400).send("Email already exists");

   //encrypt password z bcryptjs modulom
   const salt = await bcrypt.genSalt(10);
   const hashPassword = await bcrypt.hash(req.body.password, salt);

   //create new user
   const user = new User({
     email: req.body.email,
     password: hashPassword,
   });
   try {
     //save new user
     const savedUser = await user.save();
     //res.json(savedUser);
     res.json({ user: user._id });
   } catch (err) {
     res.json({ message: err });
   }
 });

   //LOGIN
   router.post("/login", async (req, res) => {
    const { error } = loginValidation(req.body);
    if (error) return res.status(400).send(error.details[0].message);

   //check if email exists
   const user = await User.findOne({ email: req.body.email });
   if (!user) return res.status(400).send("Email doesn't exist");

   //password is correct 
   const validPass = await bcrypt.compare(req.body.password, user.password);
   if (!validPass) return res.status(400).send("Invalid password");

   //create and send a json web token
   const token = jwt.sign({ _id: user._id }, secretKey, { expiresIn: "1h" });
   res.header("auth-token", token).send(token);
   res.send("Logged in!");
 });

 module.exports = router;

File: verifyToken.ts

   const jwt = require("jsonwebtoken");
   const secretKey = "f43g34gergeerg";

   module.exports = (req: any, res: any, next: any) => {
     const token = req.header("auth-token");
     if (!token) return res.status(401).send("Access denied");

     try {
       const verified = jwt.verify(token, secretKey);
       req.user = verified;
       next();
     } catch (err) {
       res.status(400).send("Invalid token");
     }
   };

My frontend (Angular) code: login.component.ts

export class LoginComponent implements OnInit {
  email: string = '';
  password: string = '';

  constructor(public authService: AuthService, private router: Router) {}

  ngOnInit(): void {}

  onLogin(form: NgForm) {
    if (form.invalid) {
      return;
    }
    this.authService.login(form.value.email, form.value.password);
    console.log(form.value);
  }
}

auth.service.ts file

   export class AuthService {
   constructor(private http: HttpClient) {}

   login(email: string, password: string) {
     const user: User = { email: email, password: password };
     this.http
       .post('http://localhost:3000/api/users/login', user)
       .subscribe((response: any) => {
         console.log(response);
       });
   }
 }

And error in web is: enter image description here

SOLVED: First error in the terminal (Cannot set headers after they are sent to the client) was solved with the accepted answer from Shivam Sood) and for solving the second error in the error tab in my browser was solved by defining responseType: 'text' in my http.post() request in my auth.service.ts file

CodePudding user response:

Error is coming from this line in your login route

res.header("auth-token", token).send(token);
res.send("Logged in!");

You are sending response twice res.send()

You will have to remove res.send("Logged in!"); in order to fix the issue.

UPDATE

I suspect the issue with angular is that, by default angular HTTP expects JSON data, but the data you are sending from backend is text. That is why parsing is failing.

You can update res.send to

res.header("auth-token", token).json({token});
  • Related