ravi
ravi

Reputation: 1220

Node Error : can't set headers after they are sent. How to solve?

After user click the login button, server closes itself by displaying an error that "Can't set headers after they are send." Any help?

Server.js file

app.put('/users/signin',function(req,res,next){
    db.collection('users',function(err,usersCollection){
        usersCollection.findOne({username:req.body.username},function(err,user){
            bcrypt.compare(req.body.password,user.password,function(err,result){
                if(result){
                    var token = jwt.encode(user,JWT_SECRET);
                    return res.json({token:token});
                }else{
                    res.status(400).send();
                }
            })
        });   
    });
    res.send();
});

Controller from where i am making call to server..

$scope.signin = function(){
                  $http.put('/users/signin',{username:$scope.username,password:$scope.password})
         .then(function(res){
               $cookies.put('token',res.data.token);
               $scope.currentUser = $scope.username;
               alert("Successfully signed in");
           },function(err){
               alert("bad login credentials");
           });
    };

Upvotes: 2

Views: 1769

Answers (1)

Emile Bergeron
Emile Bergeron

Reputation: 17430

usersCollection.findOne is async and its callback is called after res.send(); as been called.

Move the res.send(); into the bcrypt.compare callback.

app.put('/users/signin', function(req, res, next) {
    db.collection('users', function(err, usersCollection) {
        usersCollection.findOne({ username: req.body.username }, function(err, user) {
            bcrypt.compare(req.body.password, user.password, function(err, result) {
                if (result) {
                    var token = jwt.encode(user, JWT_SECRET);
                    res.json({ token: token });
                } else {
                    res.status(400);
                }

                // like here
                res.send();
            });
        });
    });
});

What's a callback?

From wikipedia, a callback is a piece of executable code that is passed as an argument to other code. There's nothing async by definition with a callback, but it's a really useful concept to use with async programming.

In JavaScript, a function can take a function reference as an argument which will serve as a callback.

function someFunction(callback) {
    console.log("before async callback");
    setTimeout(callback, 1); // calls the callback asynchronously
    console.log("after async callback");
}

It could be called like this, using an existing function

function myExistingFunction() {
    console.log("inside a callback");
}
someFunction(myExistingFunction); 

or like this, using a function expression

someFunction(function(){ 
    console.log("inside a callback");
});

Both calls to someFunction would print the following to the console in that order:

before async callback
after async callback
inside a callback

Why in that order?

Since someFunction pass the callback to the async function setTimeout, the callback is not called immediately, but only after the call stack finishes. So someFunction completely finishes, then sometime later, our callback is called.

Take a look at

Upvotes: 1

Related Questions