39

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 :)

Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • 1
    Are you actually calling the credentials page in your browser or are you making an AJAX request? – Laura Nov 29 '14 at 12:28
  • 3
    Did you ever figure out what was going on here? I'm having the same issue, validate credentials redirect doesn't work for a route specified as GET, in my case the user's profile. – OliverJ90 Aug 05 '15 at 17:08
  • No, never figured it out. I ended up building my app differently, with the login part in a modal, instead of another page... Very frustrating – Jeremy Thille Aug 06 '15 at 09:07
  • I'm having the same basic problem. I found this: http://stackoverflow.com/questions/36434978/how-to-redirect-to-another-page-in-node-js?rq=1 but it hasn't worked for me. This seems like something that Express should do quite easily and right out of the box. – Glen Pierce Mar 20 '17 at 03:59

5 Answers5

57

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.

Kelrynn
  • 588
  • 5
  • 8
  • 1
    Thanks for the answer, but this is now an old question and I'm not using jQuery any longer. I have switched to Angular 1 then Angular 2/4 a long time ago, so I'm not having this issue anymore :) Thanks anyway – Jeremy Thille Oct 16 '17 at 09:58
  • 9
    I did see that this was an old question but it was a common result for searching, so i figured I'd answer for all the people still looking for this solution. – Kelrynn Oct 20 '17 at 18:28
  • 2
    `window.location.assign('/newPath')` redirects the current page to http://localhost:3000/newPath, which worked for my case. – Friendly-Robot Nov 18 '17 at 00:20
  • This worked for me! I've been trying to get it to reroute while using AJAX and your explanation and solution helped. – mur7ay Jul 02 '18 at 04:12
6

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>)
Saswat
  • 180
  • 4
  • 13
user13074009
  • 61
  • 1
  • 1
0

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...

Community
  • 1
  • 1
Matthew Bakaitis
  • 11,600
  • 7
  • 43
  • 53
  • I forgot to mention, but I did the redirection in the callback function. I just removed Mongoose stuff for clarity. But I'm gonna give a try to your architecture, thanks :) – Jeremy Thille Nov 29 '14 at 13:25
  • If you aren't posting the code that is directly surrounding and related to the problem...I'm not sure how you'll get an answer. – Matthew Bakaitis Nov 29 '14 at 13:30
  • 2
    Sorry about that. I precisely removed the code that I believe is not related to my issue. The validation works, and the `res.redirect('/')` actually sends to the '/' route. So I believe Mongoose is not in cause here, so for clarity I removed this part. – Jeremy Thille Nov 29 '14 at 14:04
0

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.

-2

Add the following in your get / route :

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

Your browser will render file instead of downloading it

Daphoque
  • 4,421
  • 1
  • 20
  • 31