I'm using node.js to post a http request. the code works with if i define my post data ahead of the 'options' field, but if I initially set my post_data string to empty and update it later it doesn't pick up the new length. How would I get it to do that ? I'm looking to send multiple posts of varying lengths to the same place in a loop so need to be able to do this.
var post_data=''; //if i set my string content here rather than later on it works
var options = {
host: '127.0.0.1',
port: 8529,
path: '/_api/cursor',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
post_data = 'a variable length string goes here';//the change in length to post_data is not //recognised
req.write(post_data);
req.end();
'Content-Length': post_data.length
You ran this before setting post_data.
If you want to set post_data after creating the object, you'll need to set it manually later:
options.headers['Content-Length'] = post_data.length;
Note that you must set that before calling http.request().
Posting data is a matter of sending a query string (just like the way you would send it with an URL after the ?) as the request body.
This also requires to declare Content-Type and Content-Length values so the server knows how to interpret the data.
var querystring = require('querystring');
var data = querystring.stringify({
username: yourUsernameValue,
password: yourPasswordValue
});
var options = {
host: 'my.url',
port: 80,
path: '/login',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
});
});
req.write(data);
req.end();
You need to replace:
'Content-Length': post_data.length
for:
'Content-Length': Buffer.byteLength(post_data, 'utf-8')
See https://github.com/strongloop/express/issues/1870
Related
I have been trying to use native Node.JS code in Node 8 to get an access token from WSO2 with my client ID and client secret.
I receive the following error: Unsupported Client Authentication Method!
Here is my code:
const querystring = require('querystring');
const https = require('https');
var postData = querystring.stringify({
'grant_type' : 'client_credentials'
});
var options = {
hostname: 'api.somedomain.com',
port: 443,
path: '/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (data) => {
process.stdout.write(data);
});
});
req.on('error', (err) => {
console.error(err);
});
req.write(postData);
req.end();
When I attempt to include another option parameter of 'auth' for the client ID and client secret then it tells me "TypeError: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object."
Any help on how to make this work is greatly appreciated.
Looks like you are missing the Authorization header with the request. I'm no expert on javascript/node but the token generation works after adding the Authorization header in the headers section as below. I have used localhost for testing purpose.
var auth = 'Basic ' + Buffer.from("nM_ftrK2pjoBW4JofE21xI1cP0Ya" + ':' + "jmFJIgC5QMDkU_HxQKiDUbp5UAca").toString('base64');
var options = {
hostname: 'localhost',
port: 8243,
path: '/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length,
'Authorization': auth
}
};
The correct value (Authorization : Basic Base64(consumer-key:consumer-secret)) should be passed in with the token request when invoking the token endpoint to get the access_token.
Here is the sample code for my application. Why It's not working ?
Error:
"{"error":"unauthorized","error_description":"An Authentication object was not found in the SecurityContext"}"
var post_data = JSON.stringify({
'appid' : results.appid,
'appsecret': results.appsecret,
});
var url = serviceUrl+"/oauth-service/oauth/token?grant_type=client_credentials";
var post_options = {
host: url,
headers: {
'Content-Type': 'application/json'
},
data:post_data
};
const req = https.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data',function(chunk){
console.log(chunk);
});
});
req.write(post_data);
req.end();
From the HTTPS request side, you don't need to have data in post_options (the data is sent using write).
More importantly, you need to set the Content-Length header to Buffer.byteLength(post_data).
Also, the host (or hostname) field should contain just the hostname (e.g. www.facebook.com - no https:// is needed) and the rest of the URL (e.g. /oauth_service/...) should be put in the path field.
Here's an example adapted from the node.js docs. They only provide examples for http but it's mostly the same as for https:
const postData = JSON.stringify({
'msg': 'Hello World!'
});
const options = {
hostname: 'www.google.com',
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = https.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.write(postData);
req.end();
Note that without specifying which service you're working with, it's impossible to say whether you're implementing the protocol correctly (e.g. whether the URL is correct, whether your request body is correct, etc.). So if you fix the Content-Length and things still don't work, please provide more information.
I've a node.js service with /api/authenticate endpoint. I can call this service successfully from POSTMAN with 'username' and 'password' as input (body parameters). How do I call the same services from another node.js server?
With postman I get,
body: {name: 'xxxxxx', password: 'xxxxxx' }
headers: { 'content-type': 'application/x-www-form-urlencoded',
host: 'xx.xx.xx.xx:xxxx',
connection: 'close',
'content-length': '0' }
POST /api/authenticate 200 1.336 ms - 72
Following is another nodejs application ... which makes a successful request call but doesn't have any body parameters (username and password) when it reaches to the authentication server api.
var my_http = require('http');
app.get('/makeacall', function(req, res) {
var output = '';
var options = {
body: { name: 'xxxxxx', password: 'xxxxxx' },
method: 'POST',
host: 'xx.xx.xx.xx',
port: 'xxxx',
path: '/api/authenticate',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
console.log('before request');
var req = my_http.request(options, function(response) {
console.log('response is: ' + response);
console.log('Response status code: ' + response.statusCode);
response.on('data', function(chunk) {
console.log('Data ..');
output += chunk;
});
response.on('end', function(chunk) {
console.log('Whole Data ..' + output);
});
});
req.on('error', function(err) {
console.log('Error: ' + err);
});
req.end();
console.log('444');
res.send({ message: 'View record message'});
});
From this nodejs application I get empty body on the server.
body: {}
headers: { 'content-type': 'application/x-www-form-urlencoded',
host: 'xx.xx.xx.xx:xxxx',
connection: 'close',
'content-length': '0' }
POST /api/authenticate 200 1.336 ms - 72
What am I missing? Any help is appreciated.
Using stock http library of NodeJS doesn't allow you to use that syntax.
Take a look at RequestJS as a much simpler solution. It will make your life a lot easier and allow you to use the syntax you want.
This is the solution to do it with stock Node.
https://nodejs.org/api/http.html#http_http_request_options_callback
Relevant Parts:
var postData = querystring.stringify({
'msg' : 'Hello World!'
});
And then, at the end:
// write data to request body
req.write(postData);
req.end();
But use a library unless you absolutely can't.
Are you trying to get the posted data from a form/etc?
Try using express.
npm install express -save
You can get posted data from a url with the ff:
app.post('*', function(request, response){
var post = {};
if(Object.keys(request.body).length){
for(var key in request.body){
post[key] = request.body[key];
console.log(key+'=>'+post[key];
}
}
});
I'm trying to call a restlet from nodejs; it's a simple post with some authorization but all I get is some error :
{"error" : {"code" : "SYNTAX_ERROR", "message" : "SyntaxError: Empty JSON string (null$lib#3)."}}
Here's my code
request.post({
url: netSuiteUrl
headers: {
'Content-Type': 'application/json'
'Authorization': 'NLAuth nlauth_account=<account>, nlauth_email=<email>, nlauth_signature=<username>, nlauth_role=3'
}
content: '{"data":"test"}'
}, (error, response, body) ->
console.log(body)
)
The restlet actually receives the call and authorization is working. The same data I'm sending works fine with the following PHP code:
$opts = array(
'http' => array(
'method' => "POST",
'header' => "Authorization: NLAuth nlauth_account=<account>, nlauth_email=<email>, nlauth_signature=<signature>, nlauth_role=3\r\n" .
"Content-Type: application/json\r\n",
'content': '{"data":"test"}'
)
);
$context = stream_context_create($opts);
$file = file_get_contents($url, false, $context);
Any hint?
Which library do you use to send your request? Do you try with the module http of Node JS? It seems that your content isn't sent within the request.
See code below for example:
var postData = querystring.stringify({data:'test'});
var options = {
hostname: '<my host>',
port: 80,
path: '/<mypath>',
method: 'POST',
headers: {
'Content-Type': 'application/json'
'Authorization': 'NLAuth nlauth_account=<account>, nlauth_email=<email>, nlauth_signature=<username>, nlauth_role=3',
}
};
var req = http.request(options, function(res) {
// Handle successful request
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
// Handle errors
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// Send data
req.write(postData);
req.end();
Hope it helps you,
Thierry
var locationJSON, locationRequest;
locationJSON = {
latitude: 'mylat',
longitude: 'mylng'
};
locationRequest = {
host: 'localhost',
port: 1234,
path: '/',
method: 'POST',
header: {
'content-type': 'application/x-www-form-urlencoded',
'content-length': locationJSON.length
}
};
var req;
req = http.request(options, function(res) {
var body;
body = '';
res.on('data', function(chunk) {
body += chunk;
});
return res.on('end', function() {
console.log(body);
callback(null, body);
});
});
req.on('error', function(err) {
callback(err);
});
req.write(data);
req.end();
On the other end, I have a node.js server listening to port 1234 and it never gets the request. Any ideas?
You are doing req.write(data) but as far as I can see 'data' is not defined anywhere. You are also setting the 'content-length' header to locationJSON.length, which is undefined because locationJSON only has 'latitude' and 'longitude' properties.
Properly define 'data', and change the 'content-type' and 'content-length' to use that instead.
var locationJSON, locationRequest;
locationJSON = {
latitude: 'mylat',
longitude: 'mylng'
};
// convert the arguments to a string
var data = JSON.stringify(locationJSON);
locationRequest = {
host: 'localhost',
port: 1234,
path: '/',
method: 'POST',
header: {
'content-type': 'application/json', // Set the content-type to JSON
'content-length': data.length // Use proper string as length
}
};
/*
....
*/
req.write(data, 'utf8'); // Specify proper encoding for string
req.end();
Let me know if this still doesn't work.