Node.js http.request Results Back as Variable - javascript

All,
I am trying to figure out how to pass the results from an https.request in node.js code out to a variable. I have an https.request setup that correctly passes the correct information to a SOAP API and gets the correct response back. My ultimate goal is to get the output from the https.request into a variable that I can call using Express.
Here is are my code chunks.
HTML:
<div class="row">
<div class="col-md-12" class="pull-left">
<p> TEST </p>
<p>{{soapreply}}</p>
</div>
JS:
app.post('/cucmmapper/submit', function (req, res) {
// FORM - DATA COLLECTION
var cucmpub = req.body.cucmpub;
var cucmversion = req.body.cucmversion;
var username = req.body.username;
var password = req.body.password;
var authentication = username + ":" + password;
var soapreplyx = '';
// SOAP - BUILD CALL
var https = require("https");
var headers = {
'SoapAction': 'CUCM:DB ver=' + cucmversion + ' listCss',
'Authorization': 'Basic ' + new Buffer(authentication).toString('base64'),
'Content-Type': 'text/xml; charset=utf-8'
};
// SOAP - AXL CALL
var soapBody = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listCss sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'<description>?</description>' +
'<clause>?</clause>' +
'</returnedTags>' +
'</ns:listCss>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// SOAP - OPTIONS
var options = {
host: cucmpub, // IP ADDRESS OF CUCM PUBLISHER
port: 8443, // DEFAULT CISCO SSL PORT
path: '/axl/', // AXL URL
method: 'POST', // AXL REQUIREMENT OF POST
headers: headers, // HEADER VAR
rejectUnauthorized: false // REQUIRED TO ACCEPT SELF-SIGNED CERTS
};
// SOAP - Doesn't seem to need this line, but it might be useful anyway for pooling?
options.agent = new https.Agent(options);
// SOAP - OPEN SESSION
var req = https.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (d) {
soapreplyx = d;
console.log("Got Data: " + d);
});
});
// SOAP - SEND AXL CALL
req.write(soapBody);
res.render('cucmmapper-results.html'), {
'title': 'CUCM 2.1',
'soapreply': soapreplyx
};
req.end();
req.on('error', function (e) {
console.error(e);
});
});
}
The line "console.log("Got Data: " + d)" is getting the correct expected reply from the API, however, I can't figure out how to get that data into my variable "soapreplyx" which changes in Express to "soapreply".
Much appreciated for any help you might have!

You're not waiting for your request to respond before you call res.render(), so the value of soapreplyx is always '', its initial value. To correct this, add an 'end' event listener on the response object passed to your https.request() callback.
You're not appending the chunks of the response to your soapreplyx variable, you're reassigning its value with each successive chunk.
let soapRequest = https.request(options, soapResponse => {
soapResponse.on('data', chunk => {
soapreplyx += chunk
})
soapResponse.on('end', () => {
return res.render('cucmmapper-results.html', {
title: 'CUCM 2.1',
soapreply: soapreplyx
})
})
})
soapRequest.write(soapBody)
soapRequest.end()

Related

Amazon MWS- continue to get signature mismatch error even though the signature matches scratchpad (Javascript)

I am trying to send a POST request to the /Finances endpoint and cannot get past the error that says:
<ErrorResponse xmlns="http://mws.amazonservices.com/schema/Finances/2015-05-01">
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
</Error>
</ErrorResponse>
I have taken the parameters right off of successful queries on Scratchpad and run them through my hashing process and am calculating signatures that match those calculated on Scratchpad so I know my signature process is accurate but even in those instances, I am still receiving the mismatched Signature error. This tells me that maybe there is something else wrong with my request, however I've tried many different variations and mimicked the documentation with no success.
I've tried ordering my parameters in ASCII alphabetical as well as in the order that scratchpad shows (which is not alphabetical) and neither works. There are no typos in any of my keys or extra spaces. I am lost on what could be causing this and would really appreciate some help if you've worked with mws. Below is my code:
const method = "POST";
const hostName = "mws.amazonservices.com";
const requestUri = "/Finances/2015-05-01";
const keyId = XXXXXXXXXXXX;
const action = "ListFinancialEvents";
const authToken = XXXXXXXXXx;
const sellerId = XXXXXXXXX;
const secretKey = XXXXXXXXXXXx;
const signatureVersion = "2";
const timestamp = new Date();
const formattedTimestamp = timestamp.toISOString();
const version = "2015-05-01";
const signatureMethod = "HmacSHA256";
const postedAfter = "2020-06-07T0:00:00Z";
const queryString =
"AWSAccessKeyId=" +
encodeURIComponent(keyId) +
"&Action=" +
encodeURIComponent(action) +
"&MWSAuthToken=" +
encodeURIComponent(authToken) +
"&PostedAfter=" +
encodeURIComponent(postedAfter) +
"&SellerId=" +
encodeURIComponent(sellerId) +
"&SignatureMethod=" +
encodeURIComponent(signatureMethod) +
"&SignatureVersion=" +
encodeURIComponent(signatureVersion) +
"&Timestamp=" +
encodeURIComponent(formattedTimestamp) +
"&Version=" +
encodeURIComponent(version);
const stringToSign =
method + "\n" + hostName + "\n" + requestUri + "\n" + queryString;
const signature = crypto
.createHmac("sha256", secretKey)
.update(stringToSign)
.digest("base64");
const queryBody = querystring.stringify({
AWSAccessKeyId: keyId,
Action: action,
MWSAuthToken: authToken,
PostedAfter: postedAfter,
SellerId: sellerId,
SignatureMethod: signatureMethod,
SignatureVersion: signatureVersion,
Timestamp: formattedTimestamp,
Version: version,
Signature: signature,
});
const options = {
hostname: hostName,
path: requestUri,
method: method,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": queryBody.length,
Host: "mws.amazonservices.com",
"User-Agent": "myMWSApp/1.0 (Language=Javascript)",
},
};
const req = https.request(options, (res) => {
console.log("statusCode", res.statusCode);
console.log("headers:", res.headers);
res.on("data", (d) => {
process.stdout.write(d);
});
});
req.on("error", (e) => {
console.error("ERROR:", e);
});
req.write(queryBody);
req.end();

Save a http request in a variable

I have manage to get an API working for a product I have started to use, I can successfully run the below code and update a record in the api's database (I have removed all the api's soap xml code to make it look cleaner), I am trying to save the output as a variable so i can then process it in php,
I am a beginner to Javascript but I cant find much help on saving the output.
If someone could point me in the right direction I would be forever grateful,
I just need to console.log output in a variable rather than in the console.
var https = require("https");
var xml =
'<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
'<soap:Header>' +
'</soap:Header>' +
'<soap:Body>' +
'</soap:Body>' +
'</soap:Envelope>';
var username = "";
var password = "";
var options = {
host: "",
port: 443,
method: "POST",
path: "",
// authentication headers
headers: {
'Content-Type': "text/xml; charset=utf-8",
'Content-Length': Buffer.byteLength(xml),
'Authorization': "Basic " + new Buffer(username + ":" + password).toString("base64"),
'SOAPAction': "",
'Accept': "application/json"
}
};
//The call
request = https.request(options, function (res) {
console.log("statusCode:", res.statusCode);
res.on("data", (d) => {
process.stdout.write(d);
});
});
request.on("error", (e) => {
console.error(e);
});
request.end(xml);
If you want to save the output, then you need to save the data from the variable that contains the output (which you have called d).
console.log("statusCode:", res.statusCode);
var data = "";
res.on("data", (d) => {
data += d;
});
res.on("end", x => {
// data is now ready
});
Note that you will probably run into the issue described in this question and you would probably be better off using an HTTP client library that natively supported promises, such as Axios.

Sent a POST request with JS, and handling the data with Node

I'm adding a contact me section to a website. I want to be able to send the data from the forms with JS, and then receive and do something with the data with Node. I understand that there are frameworks and libraries that can handle this stuff, but I would like to build it from scratch so that I have a better understanding of what is happening.
I currently have a section of JS (see below) that is taking the form data, and sending it as a POST request to the node script, but I can't seem to wrap my head around what is happening with node, or how to receive the data with the node script. Any help in pointing me in the right direction is greatly appreciated.
const name = $(".name");
const email = $(".email");
const message = $(".message");
const submitButton = $(".submitButton");
const nameRegex = /([a-zA-Z\s-])/g;
const emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/g;
const messageRegex = /([a-zA-Z\s.,?!$%&])/gm;
const url = "../node/contactMeSubmissionHandler.js"
submitButton.click(function(){
let nameContents = name.val().match(nameRegex).join("");
let emailContents = email.val().match(emailRegex).join("");
let messageContents = message.val().match(messageRegex).join("");
// if (emailRegex.test(emailContents) == true) {
// let emailValid = emailContents;
// } else {
// console.log("Email is invalid");
// };
const data = {
email: emailContents,
name: nameContents,
message: messageContents
}
$.post(url, data, function(data, status){
console.log(`${data} and status is ${status}`);
})
})
I like to write from scratch too. Here is working code which is called from a command line to get a token.
// clientEx.js
var http = require('http');
var fs = require('fs');
const _SERVER = "dcsmail.net"; /* dcsmail.net */
// Callback function is used to deal with response
//
var callback = function (response)
{
// update stream with data
var body = '';
response.on('data', function(data) {
body += data;
});
response.on ('end', function()
{
// Data received completely.
fs.writeFileSync ("temp.lst", body, 'utf8');
// console.log ("clientEx.js received: " + body);
});
}
if ((process.argv[2] == null) || (process.argv[3] == null) || (process.argv[4] == null) || (process.argv[5] == null))
{
console.log ("clientEx.js usage:<user email> <user password> <destination> <GUID>");
}
else
{
var Ef_email = encodeURI (process.argv[2]);
var Ef_pass = encodeURI (process.argv[3]);
var Ef_dest = encodeURI (process.argv[4]);
var Ef_guid = encodeURI (process.argv[5]);
var post_data = ("f_email=" + Ef_email +
"\&" + "f_pass=" + Ef_pass +
"\&" + "f_dest=" + Ef_dest +
"\&" + "f_guid=" + Ef_guid);
// Options to be used by request
var options = {
host: _SERVER,
port: '80',
path: '/DCSM/tokenP10.php',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength (post_data)
}
};
// console.log ("clientEx.js using " + _SERVER + ":" + options.port + options.path);
// request the token from the host
try
{
var req = http.request (options, callback);
req.write (post_data);
req.end();
}
catch (error)
{
fs.writeFileSync ("temp.lst", "Host access failed\n", 'utf8');
}
}
You should be able to adapt that to your needs.
Use this code to create a server and check the log in console for different request attributes.
const http = require('http');
http
.createServer((request, response) => {
console.log(request);
response.end();
})
.listen(3000);
Make GET and POST request to http://localhost:3000/ and look for method, headers etc.
See more here and here.

POST Parse.Cloud.httpRequest with x-www-form-urlencoded fails with SyntaxError

I’m trying to execute the following Parse.Cloud.httpRequest request as part of a credit card registration (tokenisation) process:
var cardRegistrationResponse = Parse.Cloud.httpRequest({
method: 'POST',
url: cardRegistrationURL,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
'accessKeyRef': accessKey,
'cardNumber': cardInfo.number,
'cardExpirationDate': cardInfo.expirationDate,
'cardCvx': cardInfo.cvx,
'data': preRegistrationData
}
});
as part of a Parse Cloud function that I call in my iOS application using PFCloud.callFunction. But the Parse.Cloud side of thing seems to fail when doing the request (log stop right after logging all the body parameter values. See below) and the iOS side reports the following error:
2015-12-17 11:32:47.494 Nestor[37909:5680550] [Error]: Uncaught SyntaxError: Unexpected token d in <unknown file>:1 (Code: 141, Version: 1.11.0)
Here the cloud console log dumping the body parameters:
I2015-12-17T10:32:46.363Z]cardNumber: 4970100000000154
I2015-12-17T10:32:46.364Z]cardExpirationDate: 0417
I2015-12-17T10:32:46.365Z]cardCvx: 123
I2015-12-17T10:32:46.366Z]data: Qi7oou23Q8d9B3xUpjdMuYgoy_1_mCBE34uqPb7mkAmJqHGBx4ZVlLNGNPFiFYaJS4wCy-yiraxeE65tmxOe8A
I2015-12-17T10:32:46.367Z]typeof accessKeyRef is string
I2015-12-17T10:32:46.368Z]typeof cardNumber is string
I2015-12-17T10:32:46.369Z]typeof expirationDate is string
I2015-12-17T10:32:46.370Z]typeof cardCvx is string
I2015-12-17T10:32:46.371Z]typeof data is string
I have no clue what is going on. Any help will be greatly appreciated.
So to put things in context, here is the complete Parse.Cloud function:
// Register a credit card for a later use.
//
// Request params may include:
// - 'credentials': a JSON object with a bearer 'access_token'
//
// Request params must include a 'cardInfo' dictionary with the following keys:
// - 'paymentUserId': the card owner user id in the payment platform
// - 'number': the card number
// - 'expirationDate': the card expiration date in format 'MMYY'
// - 'cvx': the card security code in the format 'NNN'
// - 'currency': the card currency 3-letter code, eg 'EUR'
// - 'type': the card type, one of 'CB_VISA_MASTERCARD', 'DINERS', or 'MAESTRO'
//
// Returns a JSON object that contains the registered card info:
// - 'cardId': the id of the registered card in the payment platform
// - 'partialNumber': the partially obfuscated card number
// - 'expirationDate': the card expiration date in the format 'MMYY'
// - 'provider': the card provider, one of 'VISA', 'MASTERCARD'...
Parse.Cloud.define("registerCard", function(request, response) {
var credentials = request.params.credentials;
var cardInfo = request.params.cardInfo;
Parse.Promise.as(credentials).then(function(credentials) {
// Make sure we have credentials
if (typeof credentials === 'undefined') {
return Parse.Cloud.run("authorize")
} else {
return Parse.Promise.as(credentials)
}
}).then(function(credentials) {
// Step 1: PREREGISTRATION
var cred = Parse.Promise.as(credentials);
// var preCardRegistrationResponse = preCardRegistration(credentials, cardInfo);
console.log("Pre-registration");
console.log("CardType: " + cardInfo.type);
console.log("Currency: " + cardInfo.currency);
console.log("UserId: " + cardInfo.userId);
var preCardRegistrationResponse = Parse.Cloud.httpRequest({
method: 'POST',
url: mango_api_url + '/v2/sbsquare2015/cardRegistrations',
headers: {
'Content-Type': 'application/json;charset=utf-8',
'Authorization': 'Bearer ' + credentials.access_token
},
body: {
'CardType': cardInfo.type,
'Currency': cardInfo.currency,
// mangopay user id
'UserId': cardInfo.userId
}
});
return Parse.Promise.when(cred, preCardRegistrationResponse);
}).then(function(credentials, preCardRegistrationResponse) {
// Step 2: REGISTRATION
var cred = Parse.Promise.as(credentials);
var preCardRegistrationInfo = JSON.parse(preCardRegistrationResponse.text);
// var cardRegistrationResponse = cardRegistration(credentials, cardInfo, preCardRegistrationInfo);
var cardRegistrationURL = preCardRegistrationInfo.CardRegistrationURL;
var preRegistrationData = preCardRegistrationInfo.PreregistrationData;
var accessKey = preCardRegistrationInfo.AccessKey;
console.log("Card registration");
console.log("url: " + cardRegistrationURL);
console.log("accessKeyRef: " + accessKey);
console.log("cardNumber: " + cardInfo.number);
console.log("cardExpirationDate: " + cardInfo.expirationDate);
console.log("cardCvx: " + cardInfo.cvx);
console.log("data: " + preRegistrationData);
console.log("typeof accessKeyRef is " + (typeof accessKey) );
console.log("typeof cardNumber is " + (typeof cardInfo.number) );
console.log("typeof expirationDate is " + (typeof cardInfo.expirationDate) );
console.log("typeof cardCvx is " + (typeof cardInfo.cvx) );
console.log("typeof data is " + (typeof preRegistrationData) );
var cardRegistrationResponse = Parse.Cloud.httpRequest({
method: 'POST',
url: cardRegistrationURL,
// Default to url form encoded
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded',
// },
body: {
'accessKeyRef': accessKey,
'cardNumber': cardInfo.number,
'cardExpirationDate': cardInfo.expirationDate,
'cardCvx': cardInfo.cvx,
'data': preRegistrationData
}
});
return Parse.Promise.when(cred, cardRegistrationResponse);
}).then(function(credentials, cardRegistrationResponse) {
// Step 3: POSTREGISTRATION
var cardRegistrationInfo = JSON.parse(cardRegistrationResponse.text);
// var postCardRegistrationResponse = postCardRegistration(credentials, cardRegistrationInfo);
var cardId = cardRegistrationInfo.Id;
var postCardRegistration = Parse.Cloud.httpRequest({
method: 'PUT',
url: mango_api_url + '/v2/sbsquare2015/cardRegistration/' + cardId,
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: cardRegistrationInfo
});
return postCardRegistrationResponse;
}).then(function(postCardRegistrationResponse) {
// TRANSFORMATION
var cardRegistrationInfo = JSON.parse(postCardRegistrationResponse.text);
console.log("cardId: " + cardRegistrationInfo.CardId);
console.log("expirationDate: " + cardInfo.expirationDate);
console.log("provider: " + cardRegistrationInfo.CardProvider);
var registeredCard = {
'cardId': cardRegistration.CardId,
'partialNumber': cardInfo.number.slice(0, 6) + '******' + cardInfo.number.slice(12, 16),
'expirationDate': cardInfo.expirationDate,
'provider': cardRegistrationInfo.CardProvider
}
return Parse.Promise.as(registeredCard);
}).then(function(registeredCard) {
console.log("Registered card " + registeredCard);
response.success(registeredCard);
}, function(error) {
console.log("Card registration failed: " + error);
response.error(error);
});
});
Side note: I have the whole card registration tested in Paw and also in an iOS Swift client but I'm trying to implement it on the server side so I don't have to write an Android client as well...
But the cloud version stop during step 2 and I get the error mentioned above in my iOS client when calling the Parse Cloud function 'registerCard'.
sidenote: I'm not sure I'm using Promise the right way. I would expect the last error function to be called but it is not...
Thanks for your help
B

Uploading multipart form in pure nodejs

I have tried a bit of code to upload a file on node based server and i'm getting a socket hang up error.
After googling about the error I came across a post which suggested that request.end() if not called causes this error but as you will see code below I do have called request.end().
Any help,suggestion are appreciated
var http = require('http');
var fs = require('fs');
var options = {
hostname: 'api.built.io',
port : 443,
path : '/vi/uploads',
method : 'POST'
};
var request = http.request(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('BODY: ' + chunk);
});
});
var size;
fs.stat('/home/abhijeet/Downloads/fgo-2.jpg',function(err,stats){
size = stats.size;
console.log(size);
});
var boundaryKey = Math.random().toString(16); // random string
request.setHeader('Content-Type', 'multipart/form-data; boundary="'+boundaryKey+'"');
request.setHeader('application_api_key','1234');
request.setHeader('authtoken','123');
request.setHeader('Content-Length','42215');
// the header for the one and only part (need to use CRLF here)
request.write(
'--' + boundaryKey + '\r\n'
// use your file's mime type here, if known
+ 'Content-Type: image/jpeg\r\n'
// "name" is the name of the form field
// "filename" is the name of the original file
+ 'Content-Disposition: form-data; name="upload[upload]"; filename="/home/abhijeet/Downloads/fgo-2.jpg"\r\n'
+ 'Content-Transfer-Encoding: binary\r\n\r\n'
);
var readFile = fs.createReadStream('/home/abhijeet/Downloads/fgo-2.jpg', { bufferSize: 4 * 1024 })
.on('end', function() {
request.end('\r\n--' + boundaryKey + '--'); // mark the end of the one and only part
})
.pipe(request, { end: false }) // set "end" to false in the options so .end() isn't called on the request
request.on('error',function(error){
console.log(error);
});
// maybe write directly to the socket here?
request.end();
// console.log(readFile);

Categories