Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirecting using "pure" Node.js from inside a callback function

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.

like image 262
vrintle Avatar asked Dec 26 '18 14:12

vrintle


People also ask

What is the use redirect () function?

redirect() function lets you redirect the user to a different URL by sending an HTTP response with status 302. The HTTP client (browser, Axios, etc.) will then "follow" the redirect and send an HTTP request to the new URL as shown below.

How do you callback a function in node?

For example: In Node. js, when a function start reading file, it returns the control to execution environment immediately so that the next instruction can be executed. Once file I/O gets completed, callback function will get called to avoid blocking or wait for File I/O.

What is faster callback or promise in NodeJS?

It's a long debated hot topic between javascript developers what is efficient or fast. Till now common perception was that for getting out of callback hell we should use promises or for clean code but what about efficiency. So from my findings i assure you ES6 promises are faster and recommended than old callbacks.


1 Answers

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()">
like image 168
slebetman Avatar answered Oct 26 '22 18:10

slebetman