34

I am trying to post some json to a URL. I saw various other questions about this on stackoverflow but none of them seemed to be clear or work. This is how far I got, I modified the example on the api docs:

var http = require('http');
var google = http.createClient(80, 'server');
var request = google.request('POST', '/get_stuff',
  {'host': 'sever',  'content-type': 'application/json'});
request.write(JSON.stringify(some_json),encoding='utf8'); //possibly need to escape as well? 
request.end();
request.on('response', function (response) {
  console.log('STATUS: ' + response.statusCode);
  console.log('HEADERS: ' + JSON.stringify(response.headers));
  response.setEncoding('utf8');
  response.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

When I post this to the server I get an error telling me that it's not of the json format or that it's not utf8, which they should be. I tried to pull the request url but it is null. I am just starting with nodejs so please be nice.

Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
Mr JSON
  • 653
  • 2
  • 7
  • 6
  • 1
    Can you post the actual error message and from where you got it - from the requested server or node.js? – Thomas Dec 22 '10 at 08:27

8 Answers8

44

The issue is that you are setting Content-Type in the wrong place. It is part of the request headers, which have their own key in the options object, the first parameter of the request() method. Here's an implementation using ClientRequest() for a one-time transaction (you can keep createClient() if you need to make multiple connections to the same server):

var http = require('http')

var body = JSON.stringify({
    foo: "bar"
})

var request = new http.ClientRequest({
    hostname: "SERVER_NAME",
    port: 80,
    path: "/get_stuff",
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Content-Length": Buffer.byteLength(body)
    }
})

request.end(body)

The rest of the code in the question is correct (request.on() and below).

Ankit Aggarwal
  • 1,546
  • 10
  • 11
  • 3
    please do not use data.length, I bumped to this issue and author said do not use data.length, instead, use Buffer.byteLength(data). Ref question: http://stackoverflow.com/questions/18692580/node-js-post-causes-error-socket-hang-up-code-econnreset and ref issue: https://github.com/visionmedia/express/issues/1749 – Nam Nguyen Sep 09 '13 at 07:39
  • 1
    Updated accordingly a year late. – Ankit Aggarwal Nov 11 '14 at 05:26
  • @Tobiq - Depends. https://stackoverflow.com/questions/21297704/ascii-vs-unicode-utf-8 has good information on when one can assume ASCII is as you suspect. byteLength is more fool proof... don't need to worry about UTF8 or UTF7 or Unicode, etc. – oooyaya Sep 28 '17 at 17:03
15

Jammus got this right. If the Content-Length header is not set, then the body will contain some kind of length at the start and a 0 at the end.

So when I was sending from Node:

{"email":"joe@bloggs.com","passwd":"123456"}

my rails server was receiving:

"2b {"email":"joe@bloggs.com","passwd":"123456"} 0  "

Rails didn't understand the 2b, so it wouldn't interpret the results.

So, for passing params via JSON, set the Content-Type to application/json, and always give the Content-Length.

sidonaldson
  • 24,431
  • 10
  • 56
  • 61
10

To send JSON as POST to an external API with NodeJS... (and "http" module)

var http = require('http');

var post_req  = null,
    post_data = '{"login":"toto","password":"okay","duration":"9999"}';

var post_options = {
    hostname: '192.168.1.1',
    port    : '8080',
    path    : '/web/authenticate',
    method  : 'POST',
    headers : {
        'Content-Type': 'application/json',
        'Cache-Control': 'no-cache',
        'Content-Length': post_data.length
    }
};

post_req = http.request(post_options, function (res) {
    console.log('STATUS: ' + res.statusCode);
    console.log('HEADERS: ' + JSON.stringify(res.headers));
    res.setEncoding('utf8');
    res.on('data', function (chunk) {
        console.log('Response: ', chunk);
    });
});

post_req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
});

post_req.write(post_data);
post_req.end();
molokoloco
  • 4,504
  • 2
  • 33
  • 27
7

There is a very good library that support sending POST request in Nodejs:

Link: https://github.com/mikeal/request

Sample code:

var request = require('request');

//test data
var USER_DATA = {
    "email": "email@mail.com",
    "password": "a075d17f3d453073853f813838c15b8023b8c487038436354fe599c3942e1f95"
}

var options = {
    method: 'POST',
    url: 'URL:PORT/PATH',
    headers: {
        'Content-Type': 'application/json'
    },
    json: USER_DATA

};


function callback(error, response, body) {
    if (!error) {
        var info = JSON.parse(JSON.stringify(body));
        console.log(info);
    }
    else {
        console.log('Error happened: '+ error);
    }
}

//send request
request(options, callback);
Dio Phung
  • 5,944
  • 5
  • 37
  • 55
5

Try including the content length.

var body = JSON.stringify(some_json);
var request = google.request('POST', '/get_stuff', { 
    host: 'server',
    'Content-Length': Buffer.byteLength(body),
    'Content-Type': 'application/json' 
    });
request.write(body);
request.end();
jammus
  • 2,540
  • 23
  • 28
  • 1
    please do not use data.length, I bumped to this issue and author said do not use data.length, instead, use Buffer.byteLength(data). Ref question: http://stackoverflow.com/questions/18692580/node-js-post-causes-error-socket-hang-up-code-econnreset and ref issue: https://github.com/visionmedia/express/issues/1749 – Nam Nguyen Sep 09 '13 at 07:39
4

This might not solve your problem, but javascript doesn't support named arguments, so where you say:

request.write(JSON.stringify(some_json),encoding='utf8');

You should be saying:

request.write(JSON.stringify(some_json),'utf8');

The encoding= is assigning to a global variable, so it's valid syntax but probably not doing what you intend.

RandomEtc
  • 1,976
  • 1
  • 18
  • 17
  • actually the result of the assignment would be 'utf8' anyway so it probably *is* doing what you intend :) – RandomEtc Dec 22 '10 at 07:55
  • 'utf8' for encoding argument is obsolete anyways (default) http://nodejs.org/docs/v0.3.2/api/http.html#request.write – Thomas Dec 22 '10 at 08:25
3

Probably non-existent at the time this question was asked, you could use nowadays a higher level library for handling http requests, such as https://github.com/mikeal/request. Node's built-in http module is too low level for beginners to start with.

Mikeal's request module has built-in support for directly handling JSON (see the documentation, especially https://github.com/mikeal/request#requestoptions-callback).

jbmusso
  • 3,436
  • 1
  • 25
  • 36
1
var request = google.request(
  'POST',
  '/get_stuff',
  {
    'host': 'sever',
    **'headers'**:
    {
      'content-type': 'application/json'
    }
  }
);
Ajit S
  • 1,341
  • 1
  • 13
  • 32
Jasper Fu
  • 11
  • 1