20

What i want to do:
Simply send some data (json for example), to a node.js http server, using jquery ajax requests.

For some reason, i can't manage to get the data on the server, cause it never fires the 'data' event of the request.

Client code:

$.ajax({
    url: server,
    dataType: "jsonp",
    data: '{"data": "TEST"}',
    jsonpCallback: 'callback',
    success: function (data) {
        var ret = jQuery.parseJSON(data);
        $('#lblResponse').html(ret.msg);
    },
    error: function (xhr, status, error) {
        console.log('Error: ' + error.message);
        $('#lblResponse').html('Error connecting to the server.');
    }
});

Server code:

var http = require('http');
http.createServer(function (req, res) {

    console.log('Request received');

    res.writeHead(200, { 'Content-Type': 'text/plain' });
    req.on('data', function (chunk) {
        console.log('GOT DATA!');
    });
    res.end('callback(\'{\"msg\": \"OK\"}\')');

}).listen(8080, '192.168.0.143');
console.log('Server running at http://192.168.0.143:8080/');

As i said, it never gets into the 'data' event of the request.

Comments:
1. It logs the 'Request received' message;
2. The response is fine, im able to handle it back on the client, with data;

Any help? Am i missing something?

Thank you all in advance.

EDIT:
Commented final version of the code, based on the answer:

Client code:

$.ajax({
type: 'POST' // added,
url: server,
data: '{"data": "TEST"}',
//dataType: 'jsonp' - removed
//jsonpCallback: 'callback' - removed
success: function (data) {
    var ret = jQuery.parseJSON(data);
    $('#lblResponse').html(ret.msg);
},
error: function (xhr, status, error) {
    console.log('Error: ' + error.message);
    $('#lblResponse').html('Error connecting to the server.');
}
});


Server code:

var http = require('http');
http.createServer(function (req, res) {

    console.log('Request received');

    res.writeHead(200, { 
        'Content-Type': 'text/plain',
        'Access-Control-Allow-Origin': '*' // implementation of CORS
    });
    req.on('data', function (chunk) {
        console.log('GOT DATA!');
    });

    res.end('{"msg": "OK"}'); // removed the 'callback' stuff

}).listen(8080, '192.168.0.143');
console.log('Server running at http://192.168.0.143:8080/');


Since i want to allow Cross-Domain requests, i added an implementation of CORS.

Thanks!

Marcelo Vitoria
  • 591
  • 1
  • 5
  • 15
  • What is causing the ajax call to fire? – Eric Nov 20 '12 at 17:23
  • @Eric i have a button firing the ajax call. It's working fine, since i get the response data on the client. My problem is getting the request data on the server, which i believe it's because the 'data' event is not firing, and i don't know why. – Marcelo Vitoria Nov 20 '12 at 19:46

1 Answers1

20

To get the 'data' event to fire on the node.js server side, you have to POST the data. That is, the 'data' event only responds to POSTed data. Specifying 'jsonp' as the data format forces a GET request, since jsonp is defined in the jquery documentation as:

"jsonp": Loads in a JSON block using JSONP. Adds an extra "?callback=?" to the end of your URL to specify the callback

Here is how you modify the client to get your data event to fire.

Client:

<html>
<head>
    <script language="javascript" type="text/javascript" src="jquery-1.8.3.min.js"></script>
</head>

<body>
    response here: <p id="lblResponse">fill me in</p>

<script type="text/javascript">
$(document).ready(function() {
    $.ajax({
        url: 'http://192.168.0.143:8080',
        // dataType: "jsonp",
        data: '{"data": "TEST"}',
        type: 'POST',
        jsonpCallback: 'callback', // this is not relevant to the POST anymore
        success: function (data) {
            var ret = jQuery.parseJSON(data);
            $('#lblResponse').html(ret.msg);
            console.log('Success: ')
        },
        error: function (xhr, status, error) {
            console.log('Error: ' + error.message);
            $('#lblResponse').html('Error connecting to the server.');
        },
    });
});
</script>

</body>
</html>

Some helpful lines to help you debug the server side:

Server:

var http = require('http');
var util = require('util')
http.createServer(function (req, res) {

    console.log('Request received: ');
    util.log(util.inspect(req)) // this line helps you inspect the request so you can see whether the data is in the url (GET) or the req body (POST)
    util.log('Request recieved: \nmethod: ' + req.method + '\nurl: ' + req.url) // this line logs just the method and url

    res.writeHead(200, { 'Content-Type': 'text/plain' });
    req.on('data', function (chunk) {
        console.log('GOT DATA!');
    });
    res.end('callback(\'{\"msg\": \"OK\"}\')');

}).listen(8080);
console.log('Server running on port 8080');

The purpose of the data event on the node side is to build up the body - it fires multiple times per a single http request, once for each chunk of data that it receives. This is the asynchronous nature of node.js - the server does other work in between receiving chunks of data.

Brion Finlay
  • 554
  • 4
  • 8
  • Thanks for replying @brion-finlay. Actually, i have a button firing the ajax call. I didn't put that on the description, cause i have it working. The problem is when the request hit the server, cause it wont fire the 'data' event. – Marcelo Vitoria Nov 20 '12 at 19:38
  • I think I see - you mean the data event on the server side? The issue is that the data event on the server side occurs for POST data, but in the client you specified 'jsonp', which is a format used as a GET reply. I have modified the answer to demonstrate how you can use POST and get the data event to fire. – Brion Finlay Nov 20 '12 at 20:02
  • That's it! Thanks very much, i was missing the concept behind the use of JSONP, and the use of 'util' also helps a lot. In addition to your example, i had to change some things on the code, which i will put on a description update. Thanks! – Marcelo Vitoria Nov 20 '12 at 20:44