Jeremy Thille
Jeremy Thille

Reputation: 26370

ExpressJS : res.redirect() not working as expected?

I've been struggling for 2 days on this one, googled and stackoverflowed all I could, but I can't work it out.

I'm building a simple node app (+Express + Mongoose) with a login page that redirects to the home page. Here's my server JS code :

app
    .get('/', (req, res) => {
        console.log("Here we are : root");
        return res.sendfile(__dirname + '/index.html');
    })
    .get('/login', (req, res) => {
        console.log("Here we are : '/login'");
        return res.sendfile(__dirname + '/login.html');
    })
    .post('/credentials', (req, res) => {
        console.log("Here we are : '/credentials'");
        // Some Mongoose / DB validations
        return res.redirect('/');
    });

The login page makes a POST request to /credentials, where posted data is verified. This works. I can see "Here we are : '/credentials'" in the Node console.

Then comes the issue : the res.redirect doesn't work properly. I know that it does reach the '/' route, because :

  1. I can see "Here we are : root" in the Node console
  2. The index.html page is being sent back to the browser as a reponse, but not displayed in the window. Chrome inspector shows the POST request response, I CAN see the HTML code being sent to the browser in the inspector, but the URL remains /login and the login page is still being displayed on screen.

(Edit) The redirection is in Mongoose's callback function, it's not synchronous (as NodeJS should be). I have just removed Mongoose validation stuff for clarity.

I have tried adding res.end(), doesn't work

I have tried

req.method = 'get'; 
res.redirect('/');

and

res.writeHead(302, {location: '/'});
res.end();

Doesn't work

What am I doing wrong? How can I actually leave the '/login' page, redirect the browser to '/' and display the HTML code that it received?

Thanks a million for your help in advance :)

Upvotes: 39

Views: 83591

Answers (6)

chrisbyte
chrisbyte

Reputation: 1608

I know this is older and the upvoted answers are indeed useful; I just wanted to take it one step further and show what I do when calling my api with a JavaScript fetch call.

Assuming my backend does a res.redirect('/newpage'); the frontend checks the redirected flag in the response and if true, go to the redirected url:

Backend (node.js express)

router.get('/oldpage', function(req, res) {
  res.redirect('/newpage');
});

Frontend (JavaScript)

const api = await fetch('/oldpage');
if (api.redirected) {
  window.location.href = api.url;
}

I don't know if this is the best solution but checking for redirected and then applying the url has been working fine for me.

Upvotes: 0

user13074009
user13074009

Reputation: 61

If you are using an asynchronous request to backend and then redirecting in backend, it will redirect in backend (i.e. it will create a new get request to that URL), but won't change the URL in front end.

To make it work you need to:

  1. use window.location.href = "/url"
  2. change your async request (in front end) to simple anchor tag (<a></a>)

Upvotes: 6

nicer00ster
nicer00ster

Reputation: 63

I've been working on implementing nodemailer into my NextJS app with Express. Was having this issue and came across this. I had event.preventDefault() in my function that was firing the form to submit and that was preventing the redirect as well, I took it off and it was redirecting accordingly.

Upvotes: 0

Kelrynn
Kelrynn

Reputation: 588

The problem might not lie with the backend, but with the frontend. If you are using AJAX to send the POST request, it is specifically designed to not change your url.

Use window.location.href after AJAX's request has completed (in the .done()) to update the URL with the desired path, or use JQuery: $('body').replaceWith(data) when you receive the HTML back from the request.

Upvotes: 57

Daphoque
Daphoque

Reputation: 4678

Add the following in your get / route :

  res.setHeader("Content-Type", "text/html")

Your browser will render file instead of downloading it

Upvotes: -2

Matthew Bakaitis
Matthew Bakaitis

Reputation: 11980

It's almost certain that you are making an async call to check Mongoose but you haven't structured the code so that the redirect only happens after the async call returns a result.

In javascript, the POST would look like something this:

function validateCredentials(user, callback){
    // takes whatever you need to validate the visitor as `user`
    // uses the `callback` when the results return from Mongoose
}

app.post('/credentials', function(req, res){
    console.log("Here was are: '/credentials'";
    validateCredentials(userdata, function(err, data){
        if (err) {
            // handle error and redirect to credentials,
            // display an error page, or whatever you want to do here...
        }
        // if no error, redirect
        res.redirect('/');
    };
};

You can also see questions like Async call in node.js vs. mongoose for parallel/related problems...

Upvotes: 0

Related Questions