71

This is similar to Stream data with Node.js, but I don't feel that question was answered sufficiently.

I'm trying to use a jQuery ajax call (get, load, getJSON) to transfer data between a page and a node.js server. I can hit the address from my browser and see 'Hello World!", but when I try this from my page, it fails and shows that I get no response back. I setup a simple test page and hello world example to test this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>get test</title> 
</head>
<body>
    <h1>Get Test</h1>
    <div id="test"></div>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js"></script>
    <script>
        $(document).ready(function() {
            //alert($('h1').length);
            $('#test').load('http://192.168.1.103:8124/');
            //$.get('http://192.168.1.103:8124/', function(data) {                
            //  alert(data);
            //});
        });
    </script>
</body>
</html>

and

var http = require('http');

http.createServer(function (req, res) {
    console.log('request received');
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(8124);
Community
  • 1
  • 1
briznad
  • 914
  • 1
  • 7
  • 10
  • 1
    We need to know what is in the file you are loading - how is the code in the loaded file being executed? – mattsven Mar 21 '11 at 05:08

4 Answers4

86

If your simple test page is located on other protocol/domain/port than your hello world node.js example you are doing cross-domain requests and violating same origin policy therefore your jQuery ajax calls (get and load) are failing silently. To get this working cross-domain you should use JSONP based format. For example node.js code:

var http = require('http');

http.createServer(function (req, res) {
    console.log('request received');
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('_testcb(\'{"message": "Hello world!"}\')');
}).listen(8124);

and client side JavaScript/jQuery:

$(document).ready(function() {
    $.ajax({
        url: 'http://192.168.1.103:8124/',
        dataType: "jsonp",
        jsonpCallback: "_testcb",
        cache: false,
        timeout: 5000,
        success: function(data) {
            $("#test").append(data);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert('error ' + textStatus + " " + errorThrown);
        }
    });
});

There are also other ways how to get this working, for example by setting up reverse proxy or build your web application entirely with framework like express.

yojimbo87
  • 59,764
  • 22
  • 119
  • 130
  • Awesome, thanks! I set this up to use jsonp, as outlined in your example, and it's working perfectly. – briznad Mar 22 '11 at 06:08
  • great answer yojimbo, this really helped me out. I have posted an answer with some extra stuff. – Michael Dausmann Mar 30 '11 at 12:19
  • how building nodejs application with express will solve the cross domain request problem ? – angry kiwi Apr 19 '11 at 03:18
  • @runrunforest: if the application is entirely build on top of express, then you probably wouldn't need to make cross domain requests since everything will be served from the same origin. – yojimbo87 Apr 19 '11 at 08:12
  • Can Node.js run in "long polling" mode? I mean, constantly asking data from MySQL, while not receiving any continue the poll loop and when data is received increment the requested id to start a new "long poll" ??? Is this possible? – droplet Dec 08 '11 at 10:21
  • 1
    @Petsoukos Long polling (as a web based push technology) is possible in node.js through several modules (such as socket.io which also supports other transports), however polling MySQL directly would be highly inefficient. I would recommend to look at some pub/sub mechanism, for example the redis one which can be used for this purpose. – yojimbo87 Dec 08 '11 at 10:32
  • Hi yojimbo, your code is working fine in all browsers but when i am using same code for my android phonegap app it shows timeout, and always going to error: not in success , can you please suggest what may be the problem.Thanks in advance. – Rahul May 20 '13 at 11:04
  • @Rahul: Hi, unfortunately I have no experience with phonegap so you should ask someone who is knowledgeable in this technology. – yojimbo87 May 21 '13 at 06:34
8

Thanks to yojimbo for his answer. To add to his sample, I wanted to use the jquery method $.getJSON which puts a random callback in the query string so I also wanted to parse that out in the Node.js. I also wanted to pass an object back and use the stringify function.

This is my Client Side code.

$.getJSON("http://localhost:8124/dummy?action=dostuff&callback=?",
function(data){
  alert(data);
},
function(jqXHR, textStatus, errorThrown) {
    alert('error ' + textStatus + " " + errorThrown);
});

This is my Server side Node.js

var http = require('http');
var querystring = require('querystring');
var url = require('url');

http.createServer(function (req, res) {
    //grab the callback from the query string   
    var pquery = querystring.parse(url.parse(req.url).query);   
    var callback = (pquery.callback ? pquery.callback : '');

    //we probably want to send an object back in response to the request
    var returnObject = {message: "Hello World!"};
    var returnObjectString = JSON.stringify(returnObject);

    //push back the response including the callback shenanigans
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(callback + '(\'' + returnObjectString + '\')');
}).listen(8124);
Michael Dausmann
  • 3,448
  • 2
  • 27
  • 39
  • Your code works great. Note that you'll get a mime error with text/plain as content type. Changing content-type to application/javascript solves that. – payling Nov 29 '11 at 19:27
3

I suppose your html page is hosted on a different port. Same origin policy requires in most browsers that the loaded file be on the same port than the loading file.

Adrien
  • 9,205
  • 3
  • 24
  • 27
1

Use something like the following on the server side:

http.createServer(function (request, response) {
    if (request.headers['x-requested-with'] == 'XMLHttpRequest') {
        // handle async request
        var u = url.parse(request.url, true); //not needed

        response.writeHead(200, {'content-type':'text/json'})
        response.end(JSON.stringify(some_array.slice(1, 10))) //send elements 1 to 10
    } else {
        // handle sync request (by server index.html)
        if (request.url == '/') {
            response.writeHead(200, {'content-type': 'text/html'})
            util.pump(fs.createReadStream('index.html'), response)
        } 
        else 
        {
            // 404 error
        }
    }
}).listen(31337)
yojimbo87
  • 59,764
  • 22
  • 119
  • 130