Basic Ajax send/receive with node.js

JavascriptAjaxnode.js

Javascript Problem Overview


So I'm trying to make a very basic node.js server that with take in a request for a string, randomly select one from an array and return the selected string. Unfortunately I'm running into a few problems.

Here's the front end:

function newGame()
{
   guessCnt=0;
   guess="";
   server();
   displayHash();
   displayGuessStr();
   displayGuessCnt();
}
 
function server()
{
   xmlhttp = new XMLHttpRequest();

   xmlhttp.open("GET","server.js", true);
   xmlhttp.send();

   string=xmlhttp.responseText;
}

This should send the request to server.js:

var http = require('http');

var choices=["hello world", "goodbye world"];

console.log("server initialized");

http.createServer(function(request, response)
{
    console.log("request recieved");
    var string = choices[Math.floor(Math.random()*choices.length)];
    console.log("string '" + string + "' chosen");
    response.on(string);
    console.log("string sent");
}).listen(8001);

So clearly there are several things going wrong here:

  1. I get the feeling the way I am "connecting" these two files isn't correct both in the xmlhttp.open method and in using response.on to send the string back to the front end.

  2. I'm a little confused with how I call this page on localhost. The front end is named index.html and the sever posts to 8001. What address should I be go to on localhost in order to access the initial html page after I have initialized server.js? Should I change it to .listen(index.html) or something like that?

  3. are there other obvious problems with how I am implementing this (using .responsetext etc.)

(sorry for the long multi-question post but the various tutorials and the node.js source all assume that the user already has an understanding of these things.)

Javascript Solutions


Solution 1 - Javascript

  1. Your request should be to the server, NOT the server.js file which instantiates it. So, the request should look something like this: xmlhttp.open("GET","http://localhost:8001/", true); Also, you are trying to serve the front-end (index.html) AND serve AJAX requests at the same URI. To accomplish this, you are going to have to introduce logic to your server.js that will differentiate between your AJAX requests and a normal http access request. To do this, you'll want to either introduce GET/POST data (i.e. call http://localhost:8001/?getstring=true) or use a different path for your AJAX requests (i.e. call http://localhost:8001/getstring). On the server end then, you'll need to examine the request object to determine what to write on the response. For the latter option, you need to use the 'url' module to parse the request.

  2. You are correctly calling listen() but incorrectly writing the response. First of all, if you wish to serve index.html when navigating to http://localhost:8001/, you need to write the contents of the file to the response using response.write() or response.end(). First, you need to include fs=require('fs') to get access to the filesystem. Then, you need to actually serve the file.

  3. XMLHttpRequest needs a callback function specified if you use it asynchronously (third parameter = true, as you have done) AND want to do something with the response. The way you have it now, string will be undefined (or perhaps null), because that line will execute before the AJAX request is complete (i.e. the responseText is still empty). If you use it synchronously (third parameter = false), you can write inline code as you have done. This is not recommended as it locks the browser during the request. Asynchronous operation is usually used with the onreadystatechange function, which can handle the response once it is complete. You need to learn the basics of XMLHttpRequest. Start here.

Here is a simple implementation that incorporates all of the above:

server.js:

var http = require('http'),
      fs = require('fs'),
     url = require('url'),
 choices = ["hello world", "goodbye world"];

http.createServer(function(request, response){
    var path = url.parse(request.url).pathname;
    if(path=="/getstring"){
        console.log("request recieved");
        var string = choices[Math.floor(Math.random()*choices.length)];
        console.log("string '" + string + "' chosen");
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.end(string);
        console.log("string sent");
    }else{
        fs.readFile('./index.html', function(err, file) {  
            if(err) {  
                // write an error response or nothing here  
                return;  
            }  
            response.writeHead(200, { 'Content-Type': 'text/html' });  
            response.end(file, "utf-8");  
        });
    }
}).listen(8001);
console.log("server initialized");

frontend (part of index.html):

function newGame()
{
   guessCnt=0;
   guess="";
   server();
   displayHash();
   displayGuessStr();
   displayGuessCnt();
}

function server()
{
   xmlhttp = new XMLHttpRequest();
   xmlhttp.open("GET","http://localhost:8001/getstring", true);
   xmlhttp.onreadystatechange=function(){
         if (xmlhttp.readyState==4 && xmlhttp.status==200){
           string=xmlhttp.responseText;
         }
   }
   xmlhttp.send();
}

You will need to be comfortable with AJAX. Use the mozilla learning center to learn about XMLHttpRequest. After you can use the basic XHR object, you will most likely want to use a good AJAX library instead of manually writing cross-browser AJAX requests (for example, in IE you'll need to use an ActiveXObject instead of XHR). The AJAX in jQuery is excellent, but if you don't need everything else jQuery offers, find a good AJAX library here: http://microjs.com/. You will also need to get comfy with the node.js docs, found here. Search http://google.com for some good node.js server and static file server tutorials. http://nodetuts.com is a good place to start.

UPDATE: I have changed response.sendHeader() to the new response.writeHead() in the code above !!!

Solution 2 - Javascript

Express makes this kind of stuff really intuitive. The syntax looks like below :

var app = require('express').createServer();
app.get("/string", function(req, res) {
    var strings = ["rad", "bla", "ska"]
    var n = Math.floor(Math.random() * strings.length)
    res.send(strings[n])
})
app.listen(8001)

https://expressjs.com

If you're using jQuery on the client side you can do something like this:

$.get("/string", function(string) {
    alert(string)
})

Solution 3 - Javascript

I was facing following error with code (nodejs 0.10.13), provided by ampersand:

origin is not allowed by access-control-allow-origin

Issue was resolved changing

response.writeHead(200, {"Content-Type": "text/plain"});

to

response.writeHead(200, {
                 'Content-Type': 'text/html',
                 'Access-Control-Allow-Origin' : '*'});

Solution 4 - Javascript

Here is a fully functional example of what you are trying to accomplish. I created the example inside of hyperdev rather than jsFiddle so that you could see the server-side and client-side code.

View Code: https://hyperdev.com/#!/project/destiny-authorization

View Working Application: https://destiny-authorization.hyperdev.space/

This code creates a handler for a get request that returns a random string:

app.get("/string", function(req, res) {
    var strings = ["string1", "string2", "string3"]
    var n = Math.floor(Math.random() * strings.length)
    res.send(strings[n])
});

This jQuery code then makes the ajax request and receives the random string from the server.

$.get("/string", function(string) {
  $('#txtString').val(string);
});

Note that this example is based on code from Jamund Ferguson's answer so if you find this useful be sure to upvote him as well. I just thought this example would help you to see how everything fits together.

Solution 5 - Javascript

RESTful API (Route):

rtr.route('/testing')
.get((req, res)=>{
    res.render('test')
})
.post((req, res, next)=>{
       res.render('test')
})

AJAX Code:

$(function(){
$('#anyid').on('click', function(e){
    e.preventDefault()
    $.ajax({
        url: '/testing',
        method: 'GET',
        contentType: 'application/json',
        success: function(res){
            console.log('GET Request')
        }
    })
})

$('#anyid').on('submit', function(e){
    e.preventDefault()
    $.ajax({
        url: '/testing',
        method: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({
            info: "put data here to pass in JSON format."
        }),
        success: function(res){
            console.log('POST Request')
        }
    })
})
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaniel NillView Question on Stackoverflow
Solution 1 - JavascriptampersandView Answer on Stackoverflow
Solution 2 - JavascriptJamund FergusonView Answer on Stackoverflow
Solution 3 - JavascriptthemeView Answer on Stackoverflow
Solution 4 - JavascriptNick PainterView Answer on Stackoverflow
Solution 5 - Javascriptkartik tyagiView Answer on Stackoverflow