localStorage.setItem('auth-token', '');
This line is where the suspected error is happening. I have read other questions that receive this error that I am going to post below. I have seen it commonly where there needs to be an async or an await somewhere, and I am missing it.
Here is the full error.
(node:2211) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:547:11)
at ServerResponse.header (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/response.js:771:10)
at ServerResponse.send (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/response.js:267:15)
at checkToken (/Users/devintripp/Desktop/unt-library-system/server/controllers/user-ctrl.js:132:32)
at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
at /Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:335:12)
at next (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:275:10)
at Function.handle (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:174:3)
at router (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:47:12)
at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:317:13)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2211) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:2211) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I have boiled it down to this code.
import React, { useState, useEffect } from 'react';
import { BrowserRouter , Route, Switch } from 'react-router-dom';
import Axios from 'axios';
import { NavBar } from './components';
import SignIn from './components/auth/SignIn';
import Register from './components/auth/Register';
import { BooksList, BooksInsert, BooksUpdate } from './pages';
import UserContext from './context/UserContext'
import 'bootstrap/dist/css/bootstrap.min.css'
function App() {
//global state for the app to use
const [userData, setUserData] = useState({
token: undefined,
user: undefined
})
useEffect( () => {
const checkLoggedIn = async () => {
let token = localStorage.getItem('auth-token');
console.log(token); // this prints "" to the console in the browser
localStorage.setItem('auth-token', ''); //this code never changes the headers in chrome
if(token === null || token === ""){
localStorage.setItem('auth-token', '');
token = "";
}
const tokenResponse = await Axios.post("http://localhost:8174/user/checkToken", null, {headers: {"x-auth-token": token}});
if(tokenResponse.data){
const userRes = await Axios.get("http://localhost:8174/user/", {headers: {"x-auth-token": token}})
setUserData({token, user: userRes.data})
}
}
checkLoggedIn();
}, []);
return (
<div></div>
);
}
also a thing to note is that the localStorage.setItem() is not setting any headers to "". It is not setting headers at all.
I have read this question: Error: Can't set headers after they are sent to the client
I am not in a body or finished state, nor am I calling res.writeHead() anywhere. I could post my backend calls to /checkToken and / if that would help.
here is my checkToken and get / calls
checkToken = async (req, res) => {
try {
const token = req.header("x-auth-token")
if(!token){
res.json(false);
}
const verified = jwt.verify(token, process.env.JWT_SECRET);
if(!verified){
return res.json(false);
}
const user = await User.findById(verified.id);
if(!user){
return res.json(false)
}
return res.json(true)
} catch (err) {
return res.status(500).json({msg: err.message});
}
}
getUser = async (req, res) => {
const user = await User.findById(req.user);
// console.log(user)
if(!user){
console.log("no user found")
res.json({msg: "user not found"})
}
res.json({
name: user.name,
id: user._id
})
}
and here is where those are being called.
const express = require("express");
// const userCtrl = require("../controllers/user-ctrl");
const router = express.Router();
const UserCtrl = require("../controllers/user-ctrl");
const auth = require("../middleware/auth");
router.post('/register', UserCtrl.registerUser);
router.post('/login', UserCtrl.loginUser);
router.delete('/delete', auth, UserCtrl.deleteUser);
router.post('/checkToken', UserCtrl.checkToken);
router.get('/', auth, UserCtrl.getUser);
module.exports = router;
and lastly here is my middleware
const jwt = require('jsonwebtoken');
const auth = (req, res, next) => {
try{
const token = req.header("x-auth-token")
if(!token){
return res.status(401).json({msg: "No authentication token found, auth denied."})
}
const verified = jwt.verify(token, process.env.JWT_SECRET);
if(!verified){
return res.status(401).json({msg: "Token verification failed, auth denied."})
}
req.user = verified.id
// res.end();
next();
} catch (err) {
res.status(500).json({error: err.message});
}
}
module.exports = auth;
The answer below answered the error. I wasn't returning the responses that I was sending out so it was sending multiple responses and falling through like not putting a break; at the end of a case.
localStorage however is still an issue and is unable to be set in chrome.
It is the same issue mentioned in comments & close request.
You try to send multiple responses to the same request. Trying to send multiple responses to the same request is what causes the Express error.
This happens in your getUser
code as well as in your checkToken
code.
getUser
attempts to send multiple responses if the condition !user
is true (if user
evaluates to false
).checkToken
will attempt to send multiple responses if one of !token
, !verified
or !user
is true.