Francisco Couto Francisco Couto - 6 months ago 49
Javascript Question

NodeJS Unhandled rejection error: Can't set headers after they are sent

I've been recently envolved in a nodejs project and while trying to use promises between my database accesses and my routing I encountered the error Can't set headers after they are sent when asking for a response at http://localhost:8080/api/user . Although I'm aware of many solutions at stack none worked out for me so here is my routing code at router.js

server.get('/api/user/', function (req, res) {

database.getUser()
.then(function(data){
res.send(data);
}, function(err){

res.send(500,{error: err});
});

});


And the first part of database.js including the function getUser

(function() {

'use strict';
var Promise = require('bluebird'),
mysql = require("mysql"),
bcrypt = require('bcryptjs'),
client;

exports.connect = function(){
return new Promise(function(resolve, reject) {
client = mysql.createPool({
connectionLimit : 100,
waitForConnection: true,
host : 'localhost',
user : 'root',
password : 'root',
database : 'public',
debug : false
});
if(!client){
reject('Deu merda');
}
else{
resolve();
}
});
}


exports.getUser = function(){
return new Promise(function (resolve, reject) {
var query = "SELECT name FROM public.users";
query = mysql.format(query);
client.query(query,function (err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}


Any help would be great, thank you in advance!

EDIT: I was checking my code again and I have a middleware to check if a user has permission to access a certain page, since it is one of the last options remaining where I could be changing something here it is:

(function() {

'use strict';

var routes = require("./routes"),
cookie = require("./utils");

module.exports = function(req, res, next) {

var i;

if (req.url.split('/')[1] == 'api') {

// START REGION: API permissions (all)
for (i = 0; i < routes.api.all.length; i++) {
if (routes.api.all[i].indexOf(req.url) > -1) {
break;
}
}
if (i != routes.api.all.length) {
next();
} else {

// END REGION: API permissions (all)

// START REGION: API permissions (logged)
cookie.verifySession(req.cookies.session)
.then(function (userId) {

for (i = 0; i < routes.api.logged.length; i++) {
if (req.url.indexOf(routes.api.logged[i]) > -1) {
break;
}
}

if (i == routes.api.logged.length) {
return res.sendStatus(403);
} else {
next();
}

})
.catch(function (err) {
return res.sendStatus(403);
});

}

// END REGION: API permissions (logged)

} else {

// START REGION: Views permissions (all)

cookie.verifySession(req.cookies.session)
.catch(function (err) {
if (res.statusCode == null) {
return res.redirect('/forbidden');
}
});

for (i = 0; i < routes.views.all.length; i++) {
if (routes.views.all[i].indexOf(req.url) > -1) {
break;
}
}

if (i != routes.views.all.length) {
next();
} else {

// END REGION: Views permissions (all)

// START REGION: Views permissions (logged)

cookie.verifySession(req.cookies.session)
.then(function (userId) {

for (i = 0; i < routes.views.logged.length; i++) {
if (req.url.indexOf(routes.views.logged[i]) > -1) {
break;
}
}

if (i == routes.views.logged.length) {
if (res.statusCode == null) {
return res.redirect('/forbidden');
}
} else {
next();
}

});

}

// END REGION: Views permissions (logged)

}
next();


}
}());

I have an auxiliary file where I add the permitions:

{
"api":{
"all": [
"/api/authenticate",
"/api/user"
],

"logged": [
"/api/lessons"
],

"admin": [

]
},

"views":{
"all": [
"/",
"/user_management"
],
"logged": [],
"admin": [],
"advanced": []


}


}

Answer

I'll make my comment into an answer since this answered your question:

It looks to me like your middleware can call next() more than once.

You're calling next() at the end of the middleware function. So, any code path that hasn't hit a return before that will hit that next(). But some other code paths also have their own calls to next(). That's a double call. Basically, your middleware isn't accounting for its async operations properly and doesn't have unique logic paths that only lead to calling next() or res.redirect() only once per request.

Comments