Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nodejs Error: Parse Error at Socket.ondata

I have got some error when use http.request to make a client request(node v0.6.18, v0.6.3), the following code produces the error and I have some questions.

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

http.createServer(function(req, res) {
    var data = '多情自古空余恨';
    res.writeHead(200, {
        'Content-Type': 'text/plain',
        'Content-Length': 1 //ERROR
    });
    res.end(data);
}).listen(3000);

function request(options, callback) {
    var req = http.request(options, function(res) {
        var data = '';
        res.setEncoding = 'utf8';
        res.on('data', function(chunk) {
            data += chunk;
        });
        res.on('error', function(err) {
            callback(new Error('res error: ' + err));
        });
        res.on('end', function() {
            console.log('res on end');
            callback(null, data);
        });
    });
    req.on('socket', function(socket) {
        socket.on('error', function(err) {
            console.log('socket on error');
            callback('socket error: ' + err);
            req.abort();
        });
    });
    req.end();
}

request({
    host: 'localhost',
    port: 3000,
    method: 'GET'
}, function(err, data) {
    console.log('result, err: ' + err + ', data: ' + data);
});

Outputs:

res on end
result, err: null, data: �
socket on error
result, err: socket error: Error: Parse Error, data: undefined

Here are my questions:

  1. Why res's 'end' event happened earlier than socket's 'error' event?
  2. If I do want to callback an error when "Parse Error at Socket.ondata" happens like the above code or in any other situation, how to callback once instead of twice as the above output(IF res's 'end' event really hanppened earlier than socket's 'error' event)?

I need your help! Thanks.

===============================

I found the same code outputs:

res on end
result, err: null, data: �

in node v0.6.6 and v0.6.11. Why?

like image 429
Boris Avatar asked May 31 '12 17:05

Boris


1 Answers

Because there's a content-length header of 1, when the request receives exactly 1 octet of data, it assumes that's all there is and fires the end callback. After that, more data is received that the socket doesn't know what to do with, so it fires the error.

To work around this, you could perhaps wait a short period before firing the callback for success and track if it's been fired. For example:

var req = http.request(options, function(res) {

    var data = '';
    res.setEncoding = 'utf8';
    res.on('data', function(chunk) {
        data += chunk;
    });
    res.on('error', function(err) {
        if(!callback.called) { // check before firing the callback
          callback(new Error('res error: ' + err));
          callback.called = true; // set after firing the callback
        } // ..
    });
    res.on('end', function() {
        process.nextTick(function() { // use setTimeout if nextTick is too short
          if(!callback.called) { //..
            console.log('res on end');
            callback(null, data);
            callback.called = true; // ..
          } // ..
        }); // ..
    });
});
req.on('socket', function(socket) {
    socket.on('error', function(err) {
        if(!callback.called) { // ..
          console.log('socket on error');
          callback('socket error: ' + err);
          callback.called = true; // ..
        } // ..
        req.abort();
    });
});
req.end();

(I tried to add comments after all of the new lines to make them stand out a little.)

like image 189
Nathan Friedly Avatar answered Sep 23 '22 01:09

Nathan Friedly