10

The following is an MCVE of my server.js code:

let fs = require('fs');
let http = require('http');

http.createServer((req, res) => {
    // Handles GET requests
    if(req.method == 'GET') {
        let file = req.url == '/' ? './index.html': '/login.html'; // just an example
        fs.readFile(file, (err, data) => {
            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end(data);
        });
    } 

    // Handles POST requests
    else {
        read(status => {
            if(status) {
                res.writeHead(302, {
                    'Location': 'http://localhost:8000/login.html',
                    'Content-Type': 'text/html'
                });
                res.end();
                console.log('Redirected!');
            }
        });
    }
}).listen(8000);

// In my actual script, the `read` function reads JSON files and sends data,
// so I've used the callback function
let read = callback => fs.readFile( './index.html', (err, data) => callback(true) );

And, I've two HTML files as mentioned inside the code.

index.html

<input type="submit" onclick='let xhr = new XMLHttpRequest(); xhr.open("POST", "http://localhost:8000"); xhr.send();'>

I've used inline script to minimize traffic in my MCVE. For development purposes, I'll be using external scripts on my website

login.html

<h1>Login</h1>

Now, when I open http://localhost, index.html shows up nicely. As you've noticed that index.html is just a button. So, when I click on that button, Ajax request is fired successfully and everything works fine (no console errors) EXCEPT the fact that page does not redirects. I don't know what it going wrong or what else is missing.

I'm a beginner in Node.js and read about redirection in Nodejs - Redirect url and How to redirect user's browser URL to a different page in Nodejs?, I've searched a lot but couldn't get a hint on this. Thanks for your time!

Also, I'm aware about express, but I don't consider use of frameworks as they hide core concepts.


EDIT: When I try redirecting without the callback concept, then it works fine, as this video tells us.

vrintle
  • 5,501
  • 2
  • 16
  • 46
  • Have you checked the value of `status` when you handle the POST request? – Pointy Dec 26 '18 at 14:36
  • @Pointy `status` variable is always `true` as intended. – vrintle Dec 26 '18 at 14:39
  • why aren't you using express – iLiA Dec 26 '18 at 15:58
  • The browser won’t automatically redirect via XHR request, but you could make your JavaScript look for a “Location” header and 302 status, and if one is found, have the JavaScript redirect to the url in the Location header. – Nate Dec 28 '18 at 04:31
  • Duplicate: https://stackoverflow.com/questions/40273182/how-to-redirect-from-an-xhr-request – Quentin Jan 10 '19 at 10:21
  • @Nate — No, you can't. Redirects are handled transparently by XMLHttpRequest and fetch. – Quentin Jan 10 '19 at 10:22

2 Answers2

14

This is not an issue with node.js. It is just how browsers behave.

Ajax (XHR) does not trigger redirects in the browser. When browsers implemented XHR browser developers assumed you want control of the page refresh behaviour. Therefore they made sure XHR does not trigger any default action. All redirects will be silent and the resultant data of the redirect will be passed to your XHR object's onreadystatechange callback.

If you want redirects to trigger page refresh you can simply choose to not use XHR. Instead do a form submission:

<!-- index.html -->
<form action="http://localhost:8000" method="post">
    <input type="submit">
</form>

If instead you want to use AJAX, you will need to do the redirect in the browser like I mentioned above:

// server.js

// ...

http.createServer((req, res) => {

    // ...

    // Handles POST requests
    else {
        read(status => {
            if(status) {
                res.writeHead(200, {'Content-Type': 'application/json'});
                res.end(JSON.stringify({
                    your_response: 'here'
                }));
            }
        });
    }
}).listen(8000);

Then handle that response in the browser:

index.html

<input type="submit" onclick='let xhr = new XMLHttpRequest();xhr.addEventListener("load", function(){var response = JSON.parse(this.responseText);/* check response if you need it: */if (response.your_response === 'here') {window.location.href = 'http://localhost:8000/login.html';}});xhr.open("POST", "http://localhost:8000");xhr.send();'>

But this is crazy ugly and almost impossible to read. I'd suggest refactoring that HTML to something like this:

<!-- index.html -->

<script>
    function handleSubmit () {
      let xhr = new XMLHttpRequest();
      xhr.addEventListener("load", function(){
        var response = JSON.parse(this.responseText);

        /* check response if you need it: */
        if (response.your_response === 'here') {
          window.location.href = 'http://localhost:8000/login.html'; // REDIRECT!!
        }
      });
      xhr.open("POST", "http://localhost:8000");
      xhr.send();
    }
</script>

<input type="submit" onclick="handleSubmit()">
slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Thanks for giving time :) But, my real example of which this is an MCVE, have custom forms (div's) and it works on Ajax requests. The `login.html` is basically a HTML page that redirects the user _only_ if the credentials are correct. So, I've decided to redirect using Node.js as mentioned in attached post. – vrintle Dec 26 '18 at 14:59
  • 3
    @rv7 Redirecting using Node.js only works with the form method I show above. Otherwise you must redirect in the browser instead of Node.js – slebetman Dec 27 '18 at 03:25
  • I had started a bounty. If no answers will fulfil my wish (redirection using pure Node.js on the server-side), then I'll accept your answer. – vrintle Jan 07 '19 at 15:21
  • I believe slebetman is right. In Ajax you don't Navigate from the page to anywhere else. This can be confusing, as a classic Form Submission is a Post - but it does additional things to the root page/location itself. – John Fantastico Jan 08 '19 at 14:11
  • Correct; "redirects" are not compatible with AJAX/XHR. Back in the days of "jQuery front-end / fall-back to pure HTML", it was extremely common to see this pattern everywhere (make XHR request, if `response.result = "OK"`, redirect to `/blah`; otherwise, show an error `
    `). Nowadays with the rise of single-page apps, it's a little less common (there's no need to redirect anywhere, as there are no other pages to redirect to).
    – Elliot Nelson Jan 09 '19 at 21:34
  • "When browsers implemented XHR browser developers assumed you want control of the page refresh behaviour" — It's the same as *anything else*. If you have `` then it will load the image from the URL it redirects to, not replace the whole page. – Quentin Jan 10 '19 at 10:21
  • @Quentin XHR was not designed to replace how `img` tags work. It was designed to replace how links (`a` tag) and forms submissions work - both of which replace the whole page – slebetman Jan 10 '19 at 15:16
  • @slebetman — XHR was not designed to replace how img, a, or form elements work. It just lets you make HTTP requests from JavaScript. – Quentin Jan 10 '19 at 15:39
  • @Quentin - Yes, it was designed to replace, maybe I should have said "be and alternative method" but that's what I meant by "replace" as in you can replace a method of doing things with XHR, the link and form tags which previously were the only ways you can "make HTTP requests from Javascript". – slebetman Jan 11 '19 at 05:01
  • @Quentin OK. Forget about the replacing bit. It's still not the same as everything else since the `a` tag and form submissions replace the whole page – slebetman Jan 11 '19 at 05:03
  • @slebetman — They are designed to replace the whole page. If they point to a URL that gives a redirect response, the browser goes to the URL the response redirected it to and replaces the page with the new URL. A link loads a new page. A form loads a new page. An img puts an image in the current page. A script executes some JavaScript. XHR makes data available to JavaScript. They call get data from a URL. If the data is a redirect response they all make a new request to the new URL and do with the response whatever they were going to do with the original response if it wasn't a redirect. – Quentin Jan 11 '19 at 07:19
0

You should be using express when dealing with node js web application unless you have an internal understanding of the current node version you are using a suggestion.

Express is simple and you code would look like this (and to redirect)

app.get('/index.html',function(req,res,next){
   res.redirect('/path/to/redirect/file')
}

link: http://expressjs.com/en/4x/api.html#res.redirect