Issue
I’m creating a simple valid login check in the route with validating jwt token
In the route:
router.post("/contacts", async function (req, res, next) {
await checkLogin(req, res, next);
res.send(userController.getContacts());
});
async function checkLogin(req, res, next) {
const loggedIn = await userController.isLoggedIn(req);
if (!loggedIn) {
res.status(401).json({ error: "You are not authorized" });
}
}
In the controller
async function isLoggedIn(req) {
let token = req.header("authorization");
if (!token) {
return false;
}
token = token.substring(7); //remove Bearer from the beginning
return jwt.verify(token, tokenSecret, function (err, decoded) {
if (typeof decoded == "object" && decoded.email == req.body.email) {
return true;
} else {
return false;
}
});
}
It’s working fine with valid and invalid token but with invalid token I get this log
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
If I remove status(401)
this error log doesn’t show up. Why does it happen and how to set HTTP STATUS to 401 without triggering this error log?
Solution
You’re calling checkLogin
, which sets a status code and replies to the request. After checkLogin
finishes, the response has already been sent, and you can’t send a second response.
What you’re missing is some conditional logic that would abort processing in case the user is not logged in. Usually, this is implemented in middlewares – a middleware can intercept the request before it reaches the handler.
I can see that your checkLogin
implementation already looks a bit like a middleware function: it accepts a next
argument. You can turn it into one like this:
async function checkLogin(req, res, next) {
const loggedIn = await userController.isLoggedIn(req);
if (!loggedIn) {
res.status(401).json({ error: "You are not authorized" });
return;
}
next();
}
router.post("/contacts", checkLogin, function (req, res, next) {
res.send(userController.getContacts());
});
This tells express.js to evaluate checkLogin
middleware first, and only pass control to the handler when the middleware calls next()
. If it never calls next – control is never passed, so the "main logic" for authenticated users will never run.
Read more about middlewares here: http://expressjs.com/en/api.html#middleware-callback-function-examples