Measuring time on node.js http requests - javascript

I was wondering if we can measure the time it takes for an http request to be completed using node.js. Modifying slightly an example from the documentation (here), one can easily write down the following code.
var http = require('http');
var stamp1 = new Date();
var stamp2, stamp3, stamp4;
var options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST'
};
var req = http.request(options, function(res) {
stamp3 = new Date();
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
res.on('end', function () {
stamp4 = new Date();
console.log ("Stamp 3: " + stamp3);
console.log ("Stamp 4: " + stamp4);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
stamp2 = new Date();
console.log ("Stamp 1: " + stamp1);
console.log ("Stamp 2: " + stamp2);
Now let me come to my point. On the response one can easily measure the time it takes for the response, since in the beginning stamp3 is set and on end stamp 4 is set. So, in principle for relatively large amounts of data these two timestamps will be different.
However, the question that I have is whether stamps 1 and 2 actually measure what is happening when the request is being prepared and dispatched. In other words, is req.write(....) a synchronous operation? Based on node.js principles I would expect req.write(...) to be an asynchronous operation where one can pass an arbitrarily large document and then upon successful completion we can have a callback knowing that the request has finished.
Comments?

Two function already exist for that:
console.time(id), start the timer
console.timeEnd(id) end the timer, print id followed by the time in ms
So in your case:
var req = http.request(options, function(res) {
console.time('Requete: '); //Begin to count the time
stamp3 = new Date();
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
res.on('end', function () {
stamp4 = new Date();
console.log ("Stamp 3: " + stamp3);
console.log ("Stamp 4: " + stamp4);
console.timeEnd('Requete: '); //Will print "Requete: X" with X being the time in ms
});
});

The docs mention no callback, so I'm assuming req.write as well as res.end to be synchronous.
So in your case if you're referring to just that one request that you're initializing, I think the time measurement should be accurate. I don't expect the time difference to be very big though (perhaps even in the same milisecond).

Related

Node.js http.request Results Back as Variable

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()

How to write GET api into existing files in node.js

I'm trying to get some basic data from 2 different web api's (battery status and contacs) and write it into my .txt file
However when i do that, only one data gets written, as if it overwrites the other.
I know my code may look really bad, but im new to this and i really need help.
Code
//GET - Battery status
var options = {
host: 'www.w3.org',
port: 80,
path: '/work'
};
http.get(options, function (response) {
console.log("Response: " + response.statusCode);
console.log("Header:" + JSON.stringify(response.headers));
fs.writeFile("external-api.txt", "Responsecode:" + response.statusCode + "\nHeaders:" + JSON.stringify(response.headers))
}).on('error', function (e) {
console.log("Napaka!: " + e.message);
});
//GET ZAHTEVE - Contacts
var options = {
host: 'www.google.com',
port: 80,
path: '/work'
};
http.get(options, function (response) {
console.log("Odgovor: " + response.statusCode);
console.log("Header:" + JSON.stringify(response.headers));
fs.writeFile("external-api.txt", "Responsecode:" + response.statusCode + "\nHeaders:" + JSON.stringify(response.headers))
}).on('error', function (e) {
console.log("Napaka!: " + e.message);
});
Result
Anyone kind enough to tell me what am i doing wrong?
According to the Node.js docs:
fs.writeFile(file, data[, options], callback)
Asynchronously writes data to a file, replacing the file if it already exists. data can be a string or a buffer.
So,what you're looking for is:
fs.appendFile(file, data[, options], callback)
Asynchronously append data to a file, creating the file if it does not
yet exist. data can be a string or a buffer.
Hope this helps
Why don't you use fs.appendFile .
fs.appendFile('message.txt', 'data to append', function (err) {
});

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);

Node.js Callback Issues

Been working on a Node.js restful web service that is hosted on OpenShift. Currently I have had success with simple method calls and such, but can not seem to get the http response to work through an asynchronous callback.
Here is what I currently have:
var http = require("http");
var url = require("url"); // used to get the requested method name as well as parameters
var util = require("util");
// global variables
// router function
function route(pathname, query, callbackFunc) {
//return executeMethod(pathname, query);
var returnValue;
switch (pathname.toUpperCase()) {
case "/ADD":
returnValue = add(query['num1'], query['num2']);
//util.process.nextTick(function() {
//callbackFunc(null, returnValue);
//});
break;
case "/ADDASYNC":
//addAsync(query['num1'], query['num2'], callback);
break;
default:
returnValue = "method not found";
break;
}
//return returnValue;
//return "Route for request " + pathname + " complete, query: " + query;
}
// actual web method execution
function add(num1, num2){
//return "add method called with values: " + num1 + " " + num2;
return parseFloat(num1) + parseFloat(num2);
}
function addAsync(num1, num2, callback){
//util.process.nextTick(function(){
// var value = parseFloat(num1) + parseFloat(num2);
// util.process.nextTick(function(){
// callback(value);
// });
//});
}
// main request handler for server
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
var query = url.parse(request.url, true).query;
console.log("Request for " + pathname + " Recieved");
response.setTimeout(500);
var myCallback = function(err, data){
if(err){
response.writeHead(200, {"Content-Type": "text/plain"});
response.write('an error occured with requested method');
response.end();
}else{
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(data);
response.end();
}
}
//var finalValue = route(pathname, query);
//var finalValue = 0;
(function(){route(pathname, query, myCallback)})();
response.writeContinue();
//process.nextTick(myCallback(null, 'hello world'));
setTimeout(function(){
myCallback(null, "hello world");
}, 15);
//myCallback();
//response.writeHead(200, {"Content-Type": "text/plain"});
//response.write("Hello World. You requested: " + pathname + " with type " + pathname.type + ", value: " + finalValue);
//response.end();
}
// create the server and signal console of start
http.createServer(onRequest).listen(8080, process.env.OPENSHIFT_INTERNAL_IP);
// for debug
//http.createServer(onRequest).listen(process.env.PORT, process.env.IP);
console.log("Server has started. Listening to port: " + 8080 + " ip address: " + process.env.OPENSHIFT_INTERNAL_IP);
If I call the myCallback method directly inside the onRequest method, then I get a response back without any issues; however, calling the myCallback function inside the onRequest or route methods using process.nextTick or setTimeout does not seem to be working. I am working on this project using the Cloud9 IDE with direct git push to OpenShift so I am having some difficulties with my debug but have tried quite a few different approaches with no success, including setting the request.setTimeout function to provide some time for the timer/process event to fire. My current OpenShift app is running Node.js 0.6. Is there anything Obvious that could be causing issues that I might be missing?
I got your setTimeout to work by doing this:
comment out "response.setTimeout(500);" on line 54. It's invalid.
comment out "(function(){route(pathname, query, myCallback)})();" on line 71. Also invalid.
change timeout time to 5000 on line 76 (5000ms = 5 seconds)
For nextTick to work:
everywhere only do "process.nextTick" not "util.process.nextTick".
change line 16 to: "returnValue = add(query['num1'], query['num2']).toString();" (have to cast it as a string!)
uncomment 17, 18, 19 to see this will now work
comment out line 54, you don't need this
change line 70 to "route(pathname, query, myCallback);"
You should see what you did wrong now.

How to block after http request with Node.js

I have the following code:
var options1 = {
host: 'maps.googleapis.com',
port: 80,
path: "/maps/api/geocode/json?latlng=" + lat + "," + lng + "&sensor=false",
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
var body1 = "";
var req = http.request(options1, 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);
body1 += chunk;
});
res.on('close', function () {
console.log('get_zillow : ' + body1);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
req.end();
console.log('get_zillow : ' + body1);
I need to populate body1 with the result of the JSON response. However, the first console.log('get_zillow : ' + body1); never gets called -- for some reason the result never closes -- and the second console.log('get_zillow : ' + body1); prints nothing, since it is asynchronous and gets called before body1 gets populated.
Additionally, I need to make similar requests to different external sites several times in succession, with each request dependent on the json from the previous result. Is there any way to do this without writing three messy inner callbacks, and somehow block after an http request?
Change
res.on('close', function () {
console.log('get_zillow : ' + body1);
});
to
res.on('end', function () {
callback_function(body1);
});
//defined new function
function callback_function(finaldata)
{
// handle your final data
}

Categories