Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express redirect error: can't set headers after they are sent

When this code hits the redirect line it throws the 'Can't set headers after they are sent error' and doesn't redirect. I'm guilty of not fully understanding headers and how express works with them. This link about this error is confusing me a bit, probably because I don't have a basic enough understanding of what's going on. Also, I know this is a bit of a naive approach to authenticating, but I'm just trying to get basic things to work.

    app.post('/api/login', function(req, res) {
    if (req.body.password === auth.password) {
        auth.date = new Date()
        res.redirect('/admin')
      } else {
        console.log("wrong pw")
      }
    })

UPDATE : thank you to @Brendan Ashworth I missed an obvious else, which I've added now and no longer get the error.

However this line doesn't change the contents of my page

res.sendfile('./public/admin/views/tunes.html')

It worked before I wrapped it with the auth check

var auth = require('../config/auth')

module.exports = function(app) {

/*
 *  CONTENT API
 */

 //...

/*
 *  Admin Routes
 */
app.get('/admin/login', function(req, res) {
    res.sendfile('./public/admin/views/login.html')
})

app.post('/api/login', function(req, res) {
    if (req.body.password === auth.password) {
        auth.date = new Date()
        res.redirect('/admin')
    } else {
        res.json({message: 'Wrong password!'})
    }
})

app.get('/admin', function(req, res) {
    if (auth.date) {
        res.sendfile('./public/admin/views/tunes.html')
        console.log("test") // 
    } else { //added else
      res.redirect('/admin/login')
    }
})

app.get('/admin/:url', function(req, res) {
    if (auth.date) {
        res.sendfile('./public/admin/views/' + req.params.url + '.html')
    } else { //added else
      res.redirect('/admin/login')
    }
})

// frontend routes 
// route to handle all angular requests
app.get('*', function(req, res) {
    res.sendfile('./public/views/index.html') 
})

}

FINAL UPDATE!! The last thing I needed was to handle the redirect client side after sending the file. Simple authentication works perfectly now!

    $http.post('/api/login', $scope.auth).success(function() {
        window.location.href = '/admin'
    })
like image 220
azium Avatar asked Oct 14 '14 23:10

azium


People also ask

How do you fix Cannot set headers after they are sent to the client?

Two responses have now been sent and the Can't set headers error message occurs. The fix, in this case, would be to remove the res.json(doc1) . To send both docs back to the client the res.json() in the else could be written as res.json({ article: doc1, user: doc2 }) .

What is error captureStackTrace?

Error.captureStackTrace() A non-standard V8 function that creates the stack property on an Error instance.

How do I add a header in node JS?

setHeader(name, value) (Added in v0. 4.0) method is an inbuilt application programming interface of the 'http' module which sets a single header value for implicit headers. If this header already exists in the to-be-sent headers, its value will be replaced.

Does Res send end the function?

send doesn't return the function, but does close the connection / end the request.


1 Answers

An explanation of the error Can't set headers after they are sent error:

All HTTP responses follow this basic structure:

.. Response Line ..
.. Headers ..

.. Body ..

If you want to redirect a user, first the Response Line will be sent with a redirect code (lets say 300), then the Headers will be sent with a Location: xxx header.

Then, we can finally send a body (not in the case of a redirect, but in general). However - in the case with your code - you are sending a Body response then trying to redirect the user. Since the headers (and response line) have both already been sent (because you sent the body), it can't send more headers after the body.

An example of this in your code would be:

app.get('/admin', function(req, res) {
    if (auth.date) {
        res.sendfile('./public/admin/views/tunes.html')
    }
    res.redirect('/admin/login')
})

If I'm assuming right, you actually want to return after the res.sendfile() call. If auth.date is truthy, then you'll be sending a file (i.e. body response) and then giving a redirect code - that doesn't work.

like image 108
Brendan Avatar answered Sep 18 '22 12:09

Brendan