Counting visitors in a node http server - node.js

My source code:
var http = require("http");
var count=1;
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hi, you are number "+count+" visitors");
response.end();
count++;
}).listen(8888);
I got 1,3,5,7,..... in each visit. Why to increment the count by 2?

The request to favicon.ico is triggering an extra request (I confirmed this by logging the details for each request and then making a normal request with Chrome).
You will need to look explicitly for the type of request (url, method, etc) you're wanting to match.
Also, keep in mind, if your server dies, which it probably will at some stage, your count will be reset. If you don't want that, you should persist it somewhere less volatile, such as a database.

If your server is just a simple counter and knowing that the request to favicon.ico is triggering an extra request, then you can simple count every request as a half so it will result in exact number of visits.
counter = counter + 0.5;

You could ignore the request for the favicon.ico:
var server = http.createServer(function (req, res) {
if(req.url === '/favicon.ico'){
console.log('favicon');
return;
}
userCount++;
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('Hello!\n');
res.write('We have had ' + userCount + ' visits!\n');
res.end();
});

Related

Express.JS Get Status Code from POST Request

I am needing to find a way to get a response as a result of a https post request. So far from what I hae found that is only provided in the call back function, which does not include the result after data is written to the request and is ended as shown below:
**Note: the code below would be wrapped inside a "app.post" method.
const https = require("https");
var url = "https://someurl.com";
var options = {option1: "some option"}
var jsonData = {data1: "some data"};
const request = https.request(url, options, function (repsonse) {
// HERE THE STATUS CODE ONLY CAPTURES IF THE RESOURCE WAS AVAILABLE
// NOT IF THE REQUEST WAS SUCCESSFUL
console.log(response.statusCode);
});
request.write(jsonData);
request.end();
After the "request.end()" code i need to be able to get the status code returned from the request to determine if the actual request was successful. I would want to do something like this:
if (response.statusCode !== 200) {
res.sendFile(__dirname + "/failure.html");
}
else {
res.sendFile(__dirname + "/success.html");
}
The if statement should run after request.end() to determine if the actual request was successful. This is standard for using API frameworks such as Flask-Python, but I can't seem to find a way to catch this in express.js. Any help would be appreciated.
https.request works asynchronously. Whether the request is successful or not cannot be determined synchronously after the request.end(), but only in the callback function (where you can evaluate response.statusCode) or in the error event (if the request could not be made at all, for example because the server was unreachable).
const request = https.request(url, options, function (response) {
console.log(response.statusCode);
if (response.statusCode !== 200)
res.sendFile(__dirname + "/failure.html");
else
res.sendFile(__dirname + "/success.html");
});
request.on("error", function(err) {
console.error(err);
res.sendFile(__dirname + "/failure.html");
});
request.write(jsonData);
request.end();

response written to page only on second request

var http = require('http');
var fs = require('fs');
var path = process.argv[2];
var str="";
function onRequest(request, response) {
str += "";
console.log("Request received" + path);
fs.readdir(path, function(err, items) {
str += items;
});
response.writeHead(200, {"Context-Type": "text/plain"});
response.write(new Buffer(str).toString());
response.end();
}
http.createServer(onRequest).listen(8000);
The above snippet creates a http server which gets a directory path from the user as argument. Make a http request to get the list of files available in the directory and send them back as a response.
The response is written to the page only on the second request. The page is shown empty on the first request.
Could anyone help. Thanks in advance!!
Javascript is non blocking, so
response.writeHead(200, {"Context-Type": "text/plain"});
response.write(new Buffer(str).toString());
response.end();
will be executed before
str += items;
With
fs.readdir(path, function(err, items) {
// Handle error
str += items;
response.writeHead(200, {"Context-Type": "text/plain"});
response.write(new Buffer(str).toString());
response.end();
});
it will send the response after readdir.
And in Javascript the program will not be started for every new Request (like in PHP). So your global variable will be shared between all requests. If you don't want that put the var str=""; in onRequest.
If you have multiple routes you also want to look into something like express, because the http module doesn't include routing.

Logging with Express Node JS

I want to know what are the option of logging with Express similar to what good is to HAPI. I tried Morgan but not sure how can I log response time and other response information.
Thanks in advance for help,
Devang Desai
You could use custom token in Morgan.
For example, if you wanna log the HTTP method, status code, response time, and process ID, you could use this
// Define a custom token 'pid'
morgan.token('pid', function (request, response) { return process.pid; });
// Do the logging
app.use(morgan(function (tokens, request, response) {
var log = tokens['method'](request, response) + ' ';
log += tokens['status'](request, response) + ' ';
log += tokens['response-time'](request, response) + ' ms - PID: ' + tokens['pid'](request, response);
return log;
}));

Why are my requests being paused when they're in a loop?

I am trying to test some some examples from the book I'm reading, "Learning Node 2012". And my application for testing the server by doing 2000 requests is pausing. The tester pauses after 5 requests and sends another 5 after a certain interval. Why is it pausing? How can I fix this?
The server code:
var http = require('http');
var fs = require('fs');
// write out numbers
var counter = 0;
function writeNumbers(res)
{
for (var i = 0; i < 100; i++)
{
counter++;
res.write(counter.toString() + '\n');
}
}
// create the http server
http.createServer( function(req, res) {
var query = require('url').parse(req.url).query;
var app = require('querystring').parse(query).file + ".txt";
// content header
res.writeHead(200, { 'Content-Type': 'text/plain' } );
// write out numbers
writeNumbers(res);
// timer to open file and read contents
setTimeout(function() {
console.log('opening ' + app);
// open and read in file contents
fs.readFile(app, 'utf8', function(err, data) {
if (err)
res.write('Could not find or open file for reading\n');
else
res.write(data);
res.end();
});
}, 2000);
}).listen(3000);
console.log('Server is running on port 3000');
The spam test code:
var http = require('http');
// the url we want, plus the path and options we need
var options = {
host: 'localhost',
port: 3000,
path: '/?file=secondary',
method: 'GET'
};
var processPublicTimeline = function(response) {
// finished? ok, write the data to a file
console.log('finished request');
};
for (var i = 0; i < 2000; i++)
{
// make the request, and then end it, to close the connection
http.request(options, processPublicTimeline).end();
}
While this definitely does have some relation to Why is node.js only processing six requests at a time?
It is also because you are using a timeOut to call res.end() to close the connection/respond, and thus move onto the next connection in queue.
You should instead think about these types of things aynchronously, without the use of timeOuts, but instead with callBacks.
So your code for your two main blocks could be more like:
var counter = 0;
function writeNumbers(res, callBack){
// notice callBack argument
for (var i = 0; i < 100; i++){
counter++;
res.write(counter.toString() + '\n');
}
// execute callBack (if it exists)
if(callBack && typeof callBack === "function") callBack();
}
http.createServer( function (req, res){
var query = require('url').parse(req.url).query;
var app = require('querystring').parse(query).file + ".txt";
res.writeHead(200, { 'Content-Type': 'text/plain' } );
writeNumbers(res, function(){
// Notice this function which is passed as a callBack argument for writeNumbers to evaluate.
// This executes when the main writeNumbers portion finishes.
console.log('opening ' + app);
fs.readFile(app, 'utf8', function(err, data) {
if (err)
res.write('Could not find or open file for reading\n');
else
res.write(data);
res.end();
});
});
}).listen(3000);
Notice that your writeNumbers function now takes a callBack argument to execute when it is done, and that when you call it in your server's object, you pass a function as that callBack argument. This is one of the core patterns used very frequently in node.js/javascript applications.
This means that you aren't waiting for a timeOut to execute to end your request response, but rather it is ended as it processes your response, and moves onto the next connection immediately. This is likely to happen wayyyy quicker than 2 seconds (the amount of your timeOut). So you should see your connections being processed much quicker.
Because (as someone pointed out in your comments) your system is only able to handle a few open TCP connections at a time, you want to move through your connections as quickly as possible. Leveraging a callBack chain can help you do that when you want to do things in a certain order, or if you need to wait for certain processes to finish before executing others, without guessing with a timeOut.
Hope this helps!

Incr appears to run twice--why?

I'm having a hard time getting node, redis, and async to do what I want. I'm trying very basic things to grasp the patterns of redirecting control flow. Here, I hold a counter variable "success" that increases by one if a comparison key0 > key1 is true. They are static for now so it's always true; the only thing I wish to change is to increment success. I refresh the browser to re-run the comparison and increment success again.
My trouble is: when the page is refreshed, success jumps by 2. I tried putting a callback with incr, but it looks like only get-type commands have callbacks. I have a client.end(); in my script, but it prevented me from reloading the page so I commented it out. I suspect this is the source of my problem. If so, where does client.end belong?
var http = require("http");
var redis = require("redis");
var async = require("async");
client = redis.createClient();
http.createServer(function(request, response) {
// key "success" set to 0 externally, through redis-cli;
client.set("key0", "19");
client.set("key1", "11");
response.writeHead(200, {"Content-Type": "text/plain"});
async.series([
shortcut("key0"),
shortcut("key1"),
shortcut("success")
],
function(err, results){
if (results[0] > results[1]) {
client.incr("success", function(err, reply) {
response.write("incr done");
});
response.write(results[0] + "\n\n");
response.write(results[1] + "\n\n");
response.write(results[2]);
}
response.end();
// client.quit();
});
}).listen(8000);
function shortcut(key) {
return function(callback) {
client.get(key, function(err, reply) {
callback(null, reply);
}
);
}
}
Your browser most likely requests favicon.ico and thus generates the extra request which runs your code a second time.

Resources