NodeJS / Express: inconsistent [ERR_HTTP_HEADERS_SENT] occurring - node.js

Here I have a POST method that gets called quite often.
app.post('/return_data', async (req, res) => {
var response, file
console.log("request recieved: " + req.body.room)
await readFile('Data/'+req.body.room+'.json').then((data) => {
console.log(data)
return res.send(data)
}).catch((e) => {
console.log(e)
})
})
For some reason the response is intermittent. Sometimes it will log the following error.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:535:11)
at ServerResponse.header (/home/ec2-user/dc-floorplans/node_modules/express/lib/response.js:771:10)
at ServerResponse.send (/home/ec2-user/dc-floorplans/node_modules/express/lib/response.js:194:10)
at /home/ec2-user/dc-floorplans/app.js:127:13
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async /home/ec2-user/dc-floorplans/app.js:125:5 {
code: 'ERR_HTTP_HEADERS_SENT'
}
When I first start my web app, usually the first POST logs an error. After refreshing the page, the data comes through as intended. There is only one response in the function and so I'm puzzled as to why this error is occurring.
I know that readFile works because the data is logged in .then(). How can it be that sometimes data is sent to the client and other times it throws an error when the exact same process is happening?
Thanks in advance.
UPDATE -- FULL APP.JS:
app.set('view-engine', 'ejs');
app.use(express.urlencoded({ extended: false }))
app.use(cors())
app.use(flash())
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(methodOverride('_method'))
app.use(express.static(__dirname + '/static'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', checkAuthenticated, (req, res) => {
res.render('index.ejs');
});
app.get('/login', checkNotAuthenticated, function(req, res, next) {
res.render('login.ejs');
});
app.post('/login', checkNotAuthenticated, (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if(err) throw err
if(!user) return res.redirect('/login')
req.logIn(user, (err) => {
if(err) return next(err)
if(info.message==process.env.DEFAULTPW) {
console.log("Default password detected for: " + user.email)
return res.redirect('/')
}
return res.redirect('/')
})
})(req, res, next)
})
app.get('/update', checkAuthenticated, (req, res, next) => {
res.render('update.ejs')
})
app.post('/update', checkAuthenticated, async (req, res, next) => {
if(req.body.pw1 != req.body.pw2) { res.redirect('/update') }
if(req.body.pw2 == process.env.DEFAULTPW) { res.redirect('/update') }
const newpw = await encrypt(req.body.pw2)
var queryresult
await con.query("UPDATE login SET password = \'"+newpw+"\' WHERE email = \'"+req.body.email.toLowerCase()+"\'", (err, result, fields) => {
if (err) {
console.log(err)
return res.redirect('/update')
};
console.log(result)
queryresult = result
if(result.changedRows == 0) {
return res.redirect('/update')
}
})
return res.redirect('/')
});
app.post('/get_new_data', async (req, res) => {
console.log("New Data:")
await pollLM(req.body.room).then((data) => {
console.log(data)
return res.send(data)
}).catch((e) => {
console.log(e)
})
})
async function pollLM(room) {
return new Promise((resolve, reject) => {
const getData = pySpawn('python3.7', ['getData.py', room])
getData.stdout.on('data', (data) => {
resolve(data)
})
})
}
app.post('/return_data', async (req, res) => {
console.log("request recieved: " + req.body.room)
await readFile('Data/'+req.body.room+'.json').then((data) => {
console.log(data)
return res.send(data)
}).catch((e) => {
console.log(e)
})
})
async function readFile(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) reject(err);
console.log(typeof(data))
resolve(data)
})
})
}
app.post('/update_reload_time', (req, res) => {
console.log("reload time updated to: " + req.body.time)
fs.writeFile('Data/delay.json', JSON.stringify(req.body), () => {
console.log("delay updated to: " + req.body.time)
})
})
app.get('/reload_time', async (req, res) => {
await readFile('Data/delay.json').then((data) => {
console.log(data)
return res.send(data)
}).catch((e) => {
console.log(e)
})
})
app.delete('/logout', (req, res) => {
req.logOut()
res.redirect('/login')
})
// Page routing...
function checkAuthenticated(req, res, next) {
if(req.isAuthenticated()) {
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if(req.isAuthenticated()) {
return res.redirect('/')
}
next()
}
function encrypt(text) {
const key = crypto.scryptSync(process.env.CRYPTOPW, process.env.SALT, 24)
const cipher = crypto.createCipher('aes-192-cbc', key)
let encrypted = ''
cipher.on('readable', () => {
let chunk
while(null != (chunk = cipher.read())) {
encrypted += chunk.toString('hex')
}
})
cipher.write(text)
cipher.end()
return encrypted
}
function decrypt(text) {
const key = crypto.scryptSync(process.env.CRYPTOPW, process.env.SALT, 24)
const decipher = crypto.createDecipher('aes-192-cbc', key)
let decrypted = '';
decipher.on('readable', () => {
while(null !== (chunk = decipher.read())) {
decrypted += chunk.toString('utf8')
}
})
const encrypted = text
decipher.write(encrypted, 'hex')
decipher.end()
return decrypted
}

All you have to look for is where you response twice on the same call.
For example:
app.post('test', (req,res)=>{
res.send('1')
res.json('{1:2}')
})
will always return this error, because you are responding twice.
You have to investigate your routes one by one, I would start here:
app.post('/update', checkAuthenticated, async (req, res, next) => {
if(req.body.pw1 != req.body.pw2) { res.redirect('/update') }
if(req.body.pw2 == process.env.DEFAULTPW) { res.redirect('/update') }
const newpw = await encrypt(req.body.pw2)
var queryresult
await con.query("UPDATE login SET password = \'"+newpw+"\' WHERE email = \'"+req.body.email.toLowerCase()+"\'", (err, result, fields) => {
if (err) {
console.log(err)
return res.redirect('/update')
};
console.log(result)
queryresult = result
if(result.changedRows == 0) {
return res.redirect('/update')
}
})
return res.redirect('/')
});
You are calling res.redirect explicitly and on condition. Have you checked if both conditions meet simultaneously? I guess here is one weak point.
And I would check this one
app.post('/login', checkNotAuthenticated, (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if(err) throw err
if(!user) return res.redirect('/login')
req.logIn(user, (err) => {
if(err) return next(err)
if(info.message==process.env.DEFAULTPW) {
console.log("Default password detected for: " + user.email)
return res.redirect('/')
}
return res.redirect('/')
})
})(req, res, next)
})
Again there potentially meet two conditions. Check them out. Other parts look fine to me.

Related

modify query function in Sequelize

I'm learning "Sequelize".
I went through documentation and got this code somewhere else.
Model = require('../models/Salesman')
module.exports.creareSalesman = (req, res, next) => {
Model.create(req.body).then(
result => {
res.status.json({data: result})
}).catch(err => console.log(err))
}
but I want this in the below structure,
Model = require('../models/Salesman')
module.exports.creareSalesman = (req, res, next) => {
Model.create(req.body, function (result, err) {
if (err) {
console.log(err)
}
else {
res.status.json({data: result})
}
});
}
I tried this,.it didn't send the response. But inserted the data correctly to db.
How to get the response in this case.?
The Model.create method returns a Promise, and does not have a callback parameter.
So you either handle the Promise with then:
module.exports.creareSalesman = (req, res, next) => {
Model.create(req.body)
.then((result) => {
res.status.json({ data: result });
})
.catch((err) => console.log(err));
};
Or use async await:
module.exports.creareSalesman = async (req, res, next) => {
try {
const result = await Model.create(req.body);
res.status.json({ data: result });
} catch (err) {
console.log(err);
}
};

'req.params.id' is only accessed by first two middleware functions, but not the third. Why?

Here is the code snippet in index.js:
const { loginRequired, ensureCorrectUser } = require("./middlewares/auth");
const tasks = require("./routes/task");
app.use("/api/tasks/:id", loginRequired, ensureCorrectUser, tasks);
Here, only loginRequired and ensureCorrectUser can access the :id, but tasks can't...
Here is the code snippet from the router:
const { getTasks, addTask } = require("../handlers/task");
const router = express.Router();
router.route("/").get(getTasks).post(addTask);
module.exports = router;
auth.js:
exports.loginRequired = function (req, res, next) {
try {
let token = req.headers.authorization.split(" ")[1];
jwt.verify(token, process.env.SECRET_KEY, function (err, decoded) {
if (decoded) {
return next();
} else {
return next({
status: 401,
message: "Please login first",
});
}
});
} catch (err) {
return next({
status: 401,
message: "Please login first",
});
}
};
exports.ensureCorrectUser = function (req, res, next) {
try {
let token = req.headers.authorization.split(" ")[1];
jwt.verify(token, process.env.SECRET_KEY, function (err, decoded) {
if (decoded && decoded.id === req.params.id) {
console.log(req.params.id); //prints correct id
return next();
} else {
return next({
status: 401,
message: "Unauthorized!",
});
}
});
} catch (err) {
return next({
status: 401,
message: "Unauthorized!",
});
}
};
handler snippet:
exports.getTasks = async function (req, res, next) {
await db.User.findById(req.params.id)
.then((data) => {
console.log(req.params); //prints empty object
res.status(200).json([...data.tasks]);
})
.catch((err) => next(err));
};
exports.addTask = async function (req, res, next) {
try {
let user = await db.User.findById(req.params.id);
console.log(req.params); //prints empty object
user.tasks.push(req.body);
await user.save();
return res.status(200).json({ message: "Task Added!" });
} catch (err) {
next(err);
}
};
Why is it so..? Please help..
This thing worked finally. But it's quite messy.
router
.route("/:id")
.get(loginRequired, ensureCorrectUser, getTasks)
.post(loginRequired, ensureCorrectUser, addTask);
router.delete("/id/:id2", loginRequired, ensureCorrectUser, removeTask);
router.post("/id/complete/:id2", loginRequired, ensureCorrectUser, setComplete);

Axios.get is not returning anything in nodeJS,Express

I have a problem with .get request.
Somehow it is not returning anything? (GET http://localhost:8080/admin net::ERR_EMPTY_RESPONSE)
Any suggestions?
Get Route,With this I'm trying to filter all items by their username:
app.get("/:username", verify, (req, res) => {
console.log("Welcome to roffys server");
Todo.find({ username: req.params.username }).then((err, todo) => {
if (err) {
console.log("Error retrieving todos");
} else {
res.json(todo);
}
});
});
Verify function,here I'm verifying my auth-token,I console logged it and it is working fine:
const jwt = require("jsonwebtoken");
module.exports = function (req, res, next) {
const token = req.header("auth-token");
console.log("-----token", token);
if (!token) return res.status(401).send("Access Denied");
try {
const verified = jwt.verify(token, "secretkey");
req.user = verified;
} catch (err) {
res.status(400).send("Invalid token");
next();
}
};
FE Side with ReactJS :
componentDidMount() {
const { getAll, setPageCount } = this.props.actions;
axios
.get(`http://localhost:8080/${localStorage.getItem("username")}`, {
headers: {
"auth-token": localStorage.getItem("auth-token"),
},
})
.then((res) => {
getAll(res.data);
setPageCount();
console.log("--------res.data", res.data);
})
.catch((err) => {
console.log("err", err);
});
}
app.get("/:username", verify, (req, res, next) => {
console.log("Welcome to roffys server");
Todo.find({ username: req.params.username }).then((err, todo) => {
if (err) {
console.log("Error retrieving todos");
return next(err);
} else {
res.json(todo);
}
});
});
try to add next to your handler and call it when you receive an error.

Subscribe method does not work in angular

product-operations.component.ts
deleteProduct() {
this.productsService.delete_product(this.deleteID).subscribe((res: any) => {
console.log("helloooooo");
});
};
product.service.ts
delete_product(id) {
return this.http.delete("http://localhost:3000/delete_product/" + id);
}
backend
exports.deleteProduct = (req, res, next) => {
const id = req.param("id");
Product.deleteOne({ _id: id })
.then(() => {
console.log("deleted");
})
.catch(err => {
console.log(err);
});
};
Problem:
In the above codes, the deleteProduct function in product-operations.component.ts doesn't work properly. More precisely, it does the removal. But after doing the uninstall, subscribe doesn't run its contents. This prevents my instant update after deletion. How can I solve this?
Try to send a response back from the server.
exports.deleteProduct = (req, res, next) => {
const id = req.param("id");
Product.deleteOne({ _id: id })
.then(() => {
res.send({}) // or res.send({id: id})
console.log("deleted");
})
.catch(err => {
res.status(500)
res.send({error: err})
console.log(err);
});
};

how to properly inject middleware in NodeJS route

How can i inject my middleware function 'checkAuthenticated' into my get route below?
not sure how to properly inject the code below. Please let me know. thank you very much.
function checkAuthenticated(req, res, next) {
if(!req.header('authorization')) {
return res.status(401).send({message: 'Unauthorized request. Missing authentication header'});
}
let token = req.header('authorization').split(' ')[1];
let payload = jwt.decode(token, '123');
if(!payload) {
return res.status(401).send({message: 'Unauthorized request. Authetication header invalid'});
}
req.user = payload;
next();
}
router.route('/:user_id')
.get((req, res) => {
User.findById(req.params.user_id, (err, user) => {
if (err) {
res.send(err);
} else {
res.json(user);
}
});
})
There are a few options here. I typically use:
router.use('*', checkAuthenticated);
Another option is:
router.get('/:user_id', checkAuthenticated, (req, res) => { ... })
Or, using your example of router.route...:
router.route('/:user_id').get(checkAuthenticated, (req, res) => { ... })
You can also chain them together:
router.route('/:user_id').get(checkAuthenticated).get((req, res) => { ... })
check this hope it will help you
router.route('/:user_id')
.all((req, res, next) => {
if (req.user) {
next();
} else {
res.redirect('/');
}
})
.get((req, res) => {
res.json(req.user);
});

Resources