I am developing login and register services with Nodejs Express. Every request in postman I get same error:
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);
});
}
}
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});