I have a larger process running through a large collection of locations/devices in an API response and I'm trying to get to individual devices and turn that into a response my target system will understand. However it seems my inline HTTP request is not firing.
I've tried moving the callback out of the 'end' event, but I'm not even getting the logging for earlier up in the function. The only logging output I get is the "getting status for zone xyz"
async.each(tempSystem.zones, function(zone, zoneCallback) {
var applianceDiscovered = {};
console.log("getting status for zone", zone);
var options = {
host: host,
path: '/webapi/' + zone.zoneId + '/status',
headers: {'Authorization' : 'Bearer ' + accessToken}
};
var req = https.get(options, function(res) {
if (res.statusCode != 200) {
console.log("error ", res.statusCode);
}
console.log(res);
var bodyChunks = [];
res.on('data', function(chunk) {
bodyChunks.push(chunk);
});
res.on('end', function() {
if (res.statusCode === 200) {
console.log("get zone status: ", res.statusCode);
var body = Buffer.concat(bodyChunks);
var zoneStatus = JSON.parse(body);
console.log(zoneStatus);
zoneCallback();
} else {
console.log(res.statusCode);
}
});
res.on('error', function(error) {
console.log(error);
});
});
req.on('error', function(e) {
console.log("error: ", e);
});
}, function(err){
console.log("finished with zones");
});
Related
I have the following function in NodeJS that I use to make GET and POST calls to REST APIs
function httpRequest(options, postData) {
return new Promise(function(resolve, reject) {
const https = require('https');
var req = https.request(options, function(res) {
// reject on bad status
if (res.statusCode < 200 || res.statusCode >= 300) {
console.log('Bad status code '+res.statusCode+' '+res.statusMessage);
reject(new Error(res.statusMessage));
}else{
var body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
resolve(Buffer.concat(body).toString());
});
}
});
req.on('error', function(err) {
console.log('problem with request: ' + err.message);
reject(err);
});
if (postData) {
req.write(postData);
}
req.end();
});
}
The calls may result in a 400 Bad Request or some other error, and there is message in the returned Body. I cannot figure out how to read this body message. The variable res does not contain any property with body data and the res.on('data' event is never called so I could read the body message.
Any help is appreciated.
You will need to move a request status verification to the end event handler:
const req = https.request(options, function(res) {
const body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
const bodyString = Buffer.concat(body).toString();
if (res.statusCode < 200 || res.statusCode >= 300) {
console.log(bodyString);
reject(new Error(res.statusMessage));
} else {
resolve(bodyString);
}
});
});
Well, i'm visiting an array of urls making a request for each one, when one request ends the method executes the next. The array is something like this: [link1,link2,link3]. If i try to open first the link3 in browser i'll get an error (error 404) but opening the link1 and link2 first i'll have the desired response. In the browser works without problems, but isn't working in my code because i got "status:200" using the first two links, but a 404 with the third.
(If i open link2 and link2 in the browser the problem ends, but i want to do that not using the browser)
The code:
function websiteOpener(links_array, index, final) {
var methodStr = className + '::websiteOpener';
try {
log.info(methodStr + '>> Open the link: ' + links_array[index]);
var protocol;
var _host;
var rawhost;
if (links_array[index].match(/https:\/\/[^\/]+/)) {
rawhost = links_array[index].match(/https:\/\/[^\/]+/);
_host = rawhost[0].replace(/https:\/\//, '');
protocol = 'https:'
_path = links_array[index].replace(rawhost, '');
incremental = index + 1;
var options = {
host: _host,
path: _path,
method: 'GET',
headers: { 'Content-type': 'text/html' },
protocol: protocol,
agent: new https.Agent({
rejectUnauthorized: false,
})
}
} else {
incremental = index + 1;
var options =links_array[index];
}
if (incremental < final) {
if (links_array[index].match(/https:\/\/[^\/]+/)) {
var request = https.request(options, function (response) {
console.log(response.statusCode);
//if (response.statusCode === 200) {
var data;
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', function () {
websiteOpener(links_array, incremental, final);
});
//}
});
request.end();
} else {
var request = http.request(options, function (response) {
//if (response.statusCode === 200) {
var data;
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', function () {
websiteOpener(links_array, incremental, final);
});
//}
});
request.end();
}
} else {
options.headers = { 'Content-type': 'applcation/pdf' };
var request = https.request(options, function (response) {
console.log(response.statusCode);
//if (response.statusCode === 200) {
var data;
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', function () {
log.info(methodStr + '>>link found ' + links_array[index]);
});
//}
});
request.end();
}
} catch (e) {
log.error(methodStr + ">> Server error: ", e);
reject({ statusCode: 500, flag: 'ERR_PROCESS' });
}
}
I have an azure function with this line of code.
var myReq = https.request(options, function(res) {
context.log('STATUS: ' + res.statusCode);
context.log('HEADERS: ' + JSON.stringify(res.headers));
body += res.statusCode
res.on('data', function (chunk) {
context.log('BODY: ' + chunk);
});
});
myReq.on('error', function(e) {
context.log('problem with request: ' + e.message);
});
myReq.write(postData);
myReq.end();
But my code seems to just skip this part of code, with no errors. I am new to Azure and node.js so I might have missed some basic parts in setting this up.
Any ideas?
Edit:
Here is my full code
const https = require('https');
const querystring = require('querystring');
module.exports = async function (context, req) {
if (req.query.accessCode || (req.body && req.body.accessCode)) {
context.log('JavaScript HTTP trigger function processed a request.');
var options = {
host: 'httpbin.org',
port: 80,
path: '/post',
method: 'POST'
};
var postData = querystring.stringify({
client_id : '1234',
client_secret: 'xyz',
code: req.query.accessCode
});
var body = "";
var myReq = https.request(options, function(res) {
context.log('STATUS: ' + res.statusCode);
context.log('HEADERS: ' + JSON.stringify(res.headers));
body += res.statusCode
res.on('data', function (chunk) {
context.log('BODY: ' + chunk);
});
});
myReq.on('error', function(e) {
context.log('problem with request: ' + e.message);
});
myReq.write(postData);
myReq.end();
context.log("help");
context.res = {
status: 200,
body: "Hello " + (body)
};
} else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
Ideally it should work. You can also try using request module like below
const request = require('request');
request('http://www.google.com', function (error, response, body) {
console.error('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
});
Try and see if it helps.
Solved by doing await properly. Used this as guide.
var https = require('https');
var util = require('util');
const querystring = require('querystring');
var request = require('request')
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
/*if (req.query.name || (req.body && req.body.name)) {*/
var getOptions = {
contentType: 'application/json',
headers: {
'Authorization': <bearer_token>
},
};
var postData = {
"key": "value"
};
var postOptions = {
method: 'post',
body: postData,
json: true,
url: <post_url>,
headers: {
'Authorization': <bearer_token>
},
};
try{
var httpPost = await HttpPostFunction(context, postOptions);
var httpGet = await HttpGetFunction(context, <get_url>, getOptions);
return {
res: httpPost
};
}catch(err){
//handle errr
console.log(err);
};
};
async function HttpPostFunction(context, options) {
context.log("Starting HTTP Post Call");
return new Promise((resolve, reject) => {
var data = '';
request(options, function (err, res, body) {
if (err) {
console.error('error posting json: ', err)
reject(err)
}
var headers = res.headers;
var statusCode = res.statusCode;
//context.log('headers: ', headers);
//context.log('statusCode: ', statusCode);
//context.log('body: ', body);
resolve(body);
})
});
};
async function HttpGetFunction(context, url, options) {
context.log("Starting HTTP Get Call");
return new Promise((resolve, reject) => {
var data = '';
https.get(url, options, (resp) => {
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
})
// The whole response has been received. Print out the result.
resp.on('end', () => {
resolve(JSON.parse(data));
});
}).on("error", (err) => {
console.log("Error: " + err.message);
reject(err.message);
});
});
};
how to use Q to make it wait until previous response has come from the server.
What I am looking to do here is compare the response from test server and production server for the same request.
I get the responses back from both the servers, but unable to compare them since the assert statement is executed before the response comes back.
Any one know what I am doing wrong. heres the code.
var Q = require('q');
var path='';
var prodResponse = '';
var tstReponse = '';
Q.fcall(readFile())
.then(secondFunction())
.then(thirdFunction())
.then(function(){
console.log("prodResponse: "+prodResponse);
console.log("tstResponse: "+tstResponse);
assert.strictEqual(prodResponse, tstResponse)
})
.catch(function(){
console.log('error occurred');
})
.done();
function readFile(){
fs.readFile('hostname.json', function (err, data) {
if (err) return console.error(err);
path = JSON.parse(data);
return JSON.parse(data);
});
}
function secondFunction(){
var prodOptions = {
hostname: 'somehostname.com',
port: 80,
path: "/path?"+path.path,
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
auth : ''
};
return http.request(prodOptions, function(res) {
console.log('Prod');
res.setEncoding('utf8');
res.on('data', function (chunk) {
prodResponse = chunk;
return chunk;
});
res.on('end', function() {
console.log('No more data in response.');
})
}).on('error', function(e) {
console.log('problem with request: ' + e.message);
}).end();
}
function thirdFunction(){
// same a second, only difference is the response http.
}
There is multiple errors in your code
Q.fcall(readFile())
Your q variable is q and not Q. So this line will crash because Q is undefined (javascript is case sensitive).
Then, readFile doesn't return any promise (in fact, it returns nothing). So the q library can't use anything to wait the end of any asynchronous work. The then callbacks will be fired immediatly.
You can use Q.ninvoke to make your readFile function return a promise, and you can use Q.defer to create and return a promise from your secondFunction:
var Q = require('q');
var path='';
var prodResponse = [];
var tstReponse = '';
readFile()
.then(secondFunction())
.then(thirdFunction())
.then(function(){
console.log("prodResponse: "+prodResponse);
console.log("tstResponse: "+tstResponse);
assert.strictEqual(prodResponse, tstResponse)
})
.catch(function(){
console.log('error occurred');
})
.done();
function readFile(){
return Q.ninvoke(fs, 'readFile', 'hostname.json').then(function (data) {
path = JSON.parse(data);
return path;
}, function (err) {
console.error(err);
});
}
function secondFunction(){
var prodOptions = {
hostname: 'somehostname.com',
port: 80,
path: "/path?"+path.path,
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
auth : ''
};
var defer = Q.defer();
var chunks = [];
http.request(prodOptions, function(res) {
console.log('Prod');
res.setEncoding('utf8');
res.on('data', function (chunk) {
chunks.push(chunk);
});
res.on('end', function() {
console.log('No more data in response.');
prodResponse = chunks.join('');
defer.resolve(prodResponse);
})
}).on('error', function(e) {
console.log('problem with request: ' + e.message);
defer.reject(e);
}).end();
return defer.promise;
}
function thirdFunction(){
// same a second, only difference is the response http.
}
I am trying to invoke WCF WebService (SOAP Request) via nodejs. I am getting 415(unsupported media type) http status error code. Any idea what I am missing?
var http = require('http');
var options = {
host:'localhost',
port:'34563',
path:'/Service1.svc',
connection:'keep-alive',
accept:'*/*',
method:'POST',
header: {
'Content-Type':'text/xml;charset="UTF-8"',
'Content-Length':data.length,
'Accept':'*/*',
'SOAPAction':'http://tempuri.org/IService1/GetData'
}
};
var req=http.request(options, function(res) {
console.log(res.statusCode);
res.on('data', function(data) {
console.log(data);
});
res.on('end', function() {
});
res.on('error', function(error) {
console.log('1'+error);
});
});
var data='<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">'+
'<s:Body>'+
'<GetData xmlns="http://tempuri.org/">'+
'<value>12</value>'+
'</GetData>'+
'</s:Body>' +
'</s:Envelope>';
req.write(data);
req.end();
damn... Its silly mistake,
it supposed to be headers, 's' missed.
var options = {
host:'localhost',
port:'34563',
path:'/Service1.svc',
connection:'keep-alive',
accept:'*/*',
method:'POST',
headers: {
'Content-Type':'text/xml;charset="UTF-8"',
'Content-Length':data.length,
'Accept':'*/*',
'SOAPAction':'http://tempuri.org/IService1/GetData'
}
};
var req=http.request(options, function(res) {
console.log(res.statusCode);
var body = '';
res.on('data', function(data) {
body += data;
});
res.on('end', function() {
console.log(body);
});
res.on('error', function(error) {
console.log(error);
});
});