Node http get request can't handle Hebrew content - node.js

When using get Request, there are question mark instead of hebrew:
Bellow is a snippet of the code invoking during the request:
var req = ((/^https/.test(url))?https:http).request(opts,function(res) {
res.setEncoding('utf8');
msg.statusCode = res.statusCode;
msg.headers = res.headers;
msg.payload = "";
res.on('data',function(chunk) {
msg.payload += chunk;
});
res.on('end',function() {
node.send(msg);
node.status({});
});
});

Finally I found out the solution, although it's very specific:
we need to require iconv and correctly handle the decoding:
var req = ((/^https/.test(url))?https:http).request(opts,function(res) {
//res.setEncoding('binary');
msg.statusCode = res.statusCode;
msg.headers = res.headers;
msg.payload = "";
res.on('data',function(chunk) {
msg.payload += iconv.decode(new Buffer(chunk), "Windows-1255");
console.log(msg.payload);
});
res.on('end',function() {
node.send(msg);
node.status({});
});
});

Related

Why is my node.js function not returning SQL Server data

I have the following node.js code that is supposed to pull data from a SQL Server database. Any idea why my function is returning "Nothing to send" even though there is data to be returned from the database. What am I missing?
Your assistance will be much appreciated!
function findCasesAndSendMessage(blnExitProcess) {
var http = require('http');
options = {
host: HOST,
port: PORT,
path: '/DailySummary',
method: 'GET'
};
var req = http.request(options, function (res) {
var msg = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
msg += chunk;
});
res.on('end', async function () {
var strMessage = '';
arrRows = JSON.parse(msg);
for (var i = 0; i < arrRows.length; i++) {
objRow = arrRows[i];
strMessage += objRow.strText + "\n";
}
console.log(strMessage);
if (strMessage.length > 0) {
console.log("Message sent!");
await sendMessage(strMessage);
}
else
{
console.log("Nothing to send!");
}
if (blnExitProcess == true)
{
setTimeout(exitProcess, 10000);
}
});
});
req.end();
};

Nodejs lambda request function gets 411 Length Required

I use a node.js lambda that makes post requests to remote api, which installed on several remote locations.
I have no access to the remote api code or logs.
The lambda gets called with HTTP gateway by external application which I do not control as well.
It works perfectly for all the location but one. For one location I get this error:
411 Length Required.
I have tried to neutralize the HTTP gateway, and run lambda posts with test events.
I get the same result.
I have sent the same exact request to other locations, and got a response.
I can't find the problem as I do send a ContentLength header.
This is the lambda code:
const https = require("https");
const iconv = require("iconv-lite");
const charset = require("charset");
const qs = require("qs");
const url = require("url");
exports.handler = (event, context, callback) => {
event = JSON.parse(JSON.stringify(event));
let enc ="";
let multiValueHeaders = event["multiValueHeaders"]["Content-Type"];
let PostParams = null;
let domain = event["queryStringParameters"]["domain"] ;
let buf = Buffer.from(JSON.stringify(event["body"]), "base64");
let tstring = buf.toString("utf8");
PostParams = qs.parse(tstring);
var postData = PostParams ? qs.stringify(PostParams) : {};
let ContentLength = new Buffer.from(postData).length;
let headers = "" ;
headers += (multiValueHeaders) ? (' { "Content-Type": "'+ multiValueHeaders + '",') : '{';
headers += ('"Content-Length":'+ ContentLength + '}');
headers = JSON.parse(headers);
var q = url.parse(domain, true);
let options = {
'method': 'POST',
'hostname': q.hostname,
'path': q.pathname,
'headers': {headers}
};
var req = http.request(options, function (res) {
let chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
enc = charset(res.headers, chunk);
});
res.on("end", function (chunk) {
var decodedBody = iconv.decode(Buffer.concat(chunks), enc);
const response = {
statusCode: 200,
body: decodedBody
};
callback(null ,response );
});
res.on("error", function (error) {
console.error(error);
});
});
if (PostParams != null) req.write(postData);
req.end();
}
When a request sent to the endpoint straight form postman there is no error. Only from lambda.
Apart from why this event = JSON.parse(JSON.stringify(event));?
Apart from this is a very ugly way to build the headers object:
let headers = "";
headers += (multiValueHeaders) ? (' { "Content-Type": "'+ multiValueHeaders + '",') : '{';
headers += ('"Content-Length":'+ ContentLength + '}');
headers = JSON.parse(headers);
and I would have written as:
const headers = { "Content-Length": ContentLength };
if(multiValueHeaders) headers["Content-Type"] = multiValueHeaders;
The root cause of your problem is in this line:
'headers': {headers}
it needs to be changed in:
'headers': headers
Hope this helps
411 is returned when the server demands a valid Content-Length
event argument passed through the HTTP gateway is the entire client request object. You don't have to parse it.
event.body is an escaped string. Double-escaping it gives the wrong content-length. For example,
JSON.stringify({'double': 2}) !== JSON.stringify(JSON.stringify({'double': 2))
// false
With this in mind, you can perform your request like this:
exports.handler = (event, context, callback) => {
let enc = "";
let multiValueHeaders = event["multiValueHeaders"];
let domain = event["queryStringParameters"]["domain"] ;
const postHeaders = {...multiValueHeaders};
let postData = null;
if (event.body !== null) {
postData = qs.stringify(
qs.parse(
Buffer.from(event.body, "base64").toString("utf-8")
)
);
postHeaders['Content-Length'] = [ Buffer.byteLength(postData) ];
}
var q = url.parse(domain, true);
let options = {
'method': 'POST',
'hostname': q.hostname,
'path': q.pathname,
'headers': postHeaders
};
var req = http.request(options, function (res) {
let chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
enc = charset(res.headers, chunk);
});
res.on("end", function (chunk) {
var decodedBody = iconv.decode(Buffer.concat(chunks), enc);
const response = {
statusCode: 200,
body: decodedBody
};
callback(null, response);
});
res.on("error", function (error) {
console.error(error);
});
});
if (postData !== null) req.write(postData);
req.end();
}

multiple get requests in node js

I'm working on a facebook chatbot. I have to make several GET requests according to users response. Right now I'm making all requests at once, since I don't know how to get the response out of the request function. Is there an easier way to it?
'use strict';
var https = require('https');
var options = {
host: 'url.com',
path: '/path_to_api'
};
var req = https.get(options, function(res) {
var bodyChunks = [];
res.on('data', function(chunk) {
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
body = ''+body;
var json_body = JSON.parse(body);
var options2 = {
host: 'url2.com',
path: '/path_to_api'
};
var req = https.get(options2, function(res) {
var bodyChunks = [];
res.on('data', function(chunk) {
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
body = ''+body;
var json_body2 = JSON.parse(body);
})
});
Thanks
You can try create a bunch of requests with request-promise:
var rp = require('request-promise');
var requests = [
rp(options), rp(options2), rp(options3) ...
];
Promise.all(requests).then(([restul1, result2, ...allOtherResuts]) => {
//process ok
}).catch( err => {
//handle error
})

aws lambda calling external API showing error when it is working

Using a lambda calling an external API....Populating the POST with a JSON of an xml file.
API call: https:serverName/api/SyncPersonnelViaAwsApi/SapEaiCall
Hits the API function and returns the correct message 'Not latest version of file, update not performed'
However the lambda says it has failed.
Response:
{
"errorMessage": "\"{'response' : 'Not latest version of file, update not performed'}\""
}
this is all the data that is given in the logs...but this is the correct message postback...does anyone have any idea why it is still flagging as a fail?
(code below)
//// POST api/<controller>
public string SapEaiCall([FromBody]string xmlFile)
{
string responseMsg = "Failed Import Active Directory User";
if (string.IsNullOrEmpty(xmlFile))
{
responseMsg = "XML file is NULL";
}
if (responseMsg != "XML file is NULL")
{
xmlFile = RemoveFirstAndLastQuotes(xmlFile);
if (!IsNewestVersionOfXMLFile(xmlFile))
{
responseMsg = "Not latest version of file, update not performed";
}
else
{
Business.PersonnelReplicate personnelReplicate = BusinessLogic.SynchronisePersonnel.BuildFromDataContractXml<Business.PersonnelReplicate>(xmlFile);
bool result = Service.Personnel.SynchroniseCache(personnelReplicate);
if (result)
{
responseMsg = "Success Import Sap Cache User";
}
}
}
return "{\"response\" : \" " + responseMsg + " \" , \"isNewActiveDirectoryUser\" : \" false \"}";
}
(lambda:)
var querystring = require('querystring');
var https = require('https');
var fs = require('fs');
exports.handler = function(event, context) {
const post_data = JSON.stringify('="xmlData"');
// An object of options to indicate where to post to
var post_options = {
host: 'ServerName',
protocol: 'https:',
// port: '443',
path: '/api/SyncPersonnelViaAwsApi/SapEaiCall',
method: 'POST',
json:post_data,
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
};
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var post_request = https.request(post_options, function(res) {
var body = "";
res.on('data', function(chunk) {
//chunk = '456';
body += chunk;
});
res.on('end', function() {
context.done(body);
});
res.on('error', function(e) {
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
console.log("posted data " +post_data);
};
context.done() takes two parameters. The first one is the error object and the second is response object on success. Change
res.on('end', function() {
context.done(body);
});
to
res.on('end', function() {
context.done(null, body);
});

multiple http get calls nodejs

Thanks for looking into the code.
Here I am fetching some data using feed parser and taking out id's in navcodes array variable and wants to use these Id to make http call.Please find code below.
function processNavCode(){
var mfId = [53];
var preTitle = '';
var navCodes = [];
mfId.forEach(function(id){
var query = "http://portal.xyz.com/Rss.aspx?mf="+id;
feed(query, function(err, feeds) {
if (err) {
throw err;
}
feeds.forEach(function(feed){
var link = feed.link;
var title = feed.title;
var navCode = link.substr(link.length - 6);
if(title.split('-')[0].trim() != preTitle){
preTitle = title;
counter ++;
}
if(parseInt(navCode) != '')
navCodes.push = parseInt(navCode);
});
});
async.eachSeries(navCodes,insertbulkMFValues,function(){
console.log('I am done');
});
// insertbulkMFValues(navCode);
//Directly call insertbulkMFValues function
});
}
I have also tried to call the insertbulkMFValues directly as commented now but due to async nature of nodejs, I am getting the error of either 'Socket hang up' or 'read ECONNRESET'. I checked and used async but not able to work with that also.
var insertbulkMFValues =function(navCode,callback){
var options = {
host: 'www.quandl.com',
path: '/api/v3/datasets/AMFI/'+navCode+'.json?api_key=123456789&start_date=2013-08-30',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
var req1 = https.request(options, function(response) {
var body = '';
response.setEncoding('utf8');
response.on('data', function(chunk) {
body += chunk;
});
response.on('end', function() {
if(typeof body === "string") {
var json = JSON.parse(body);
}
var mfData = json.dataset.data;
var schemeId = json.dataset.dataset_code;
var schemeName = json.dataset.name;
var isinCode = json.dataset.description;
var valueData=[];
for (var k = 0; k < mfData.length; k++) {
var myDate = new Date(mfData[k][0]);
valueData.push({
date:myDate,
NAV:parseFloat(mfData[k][1]).toFixed(2)
});
}
var query = { "navCode": schemeId };
var newData = {
createdDate: Date.now(),
navCode: schemeId,
schemeCode:count,
schemeName:schemeName,
ISINCode:isinCode,
values:valueData
};
MHistory.findOneAndUpdate(query, newData , {upsert:true}, function(err, doc){
if(err)
console.log('Errorr');
else
console.log('Success');
});
});
});
req1.on('error', function(e) {
console.log('problem with request: ' + e.message);
callback(true);
});
req1.end();
}
Thanks in advance..
J
You can directly call insertbulkMFValues for each navCode like:
if(parseInt(navCode) != '') {
insertbulkMFValues(navCode, function () {
console.log('something'}
});
}
Anything that you intend to do must be within the callback of the asynchronous function.
One option for you is to use the waterfall or parallel method of the async library to retrieve all feeds for each id and then invoke
async.eachSeries(navCodesAccumulated,insertbulkMFValues,function(){
console.log('I am done');
});
within the final result callback using the codes obtained.

Resources