AllNode JS

Fully Functional NodeJS static + Dynamic Server

Off late I have seen many people struggling with creating a static Node server, also there have been questions like “How to have static & Dynamic files served by Node”. So here I have a fully functional server that can serve both static as well as dynamic files. Off course there is no need as there are many frameworks that can take care of these things. But always good to do things on your own to learn a new language or as we say Reinventing the wheels.
Below is the server that decides what content to serve based on URL. I have used /static/ to mark static content from URL pattern. That is any URL having this pattern would be considered static and would be served from file system.

var http = require('http'),
url = require('url'),
staticHandler = require('./staticHandler');
function start(router, handlers)
{
http.createServer(function(req, res) {
var _url = url.parse(req.url).pathname;
if(_url.indexOf('/static/') != -1)
{
staticHandler.handleStatic(_url, res);
return;
}
else
{
var content = router(handlers, _url, req);
res.writeHead(200, {"Content-Type": "text/html"});
res.write(content);
res.end();
}
}).listen(8888);
console.log("Server started !! ");
}
exports.start = start;

Most of the code here is self explanatory, in case you are missing something I recommend you to read this post.
We now would be creating a static handler to pipe the file to the output stream.

var path = require('path'),
fs = require('fs');
function handleStatic(pageUrl, response)
{
var filename = path.join(process.cwd(), pageUrl);
path.exists(filename, function(exists) {
if(!exists) {
console.log("not exists: " + filename);
response.writeHead(404, {'Content-Type': 'text/html'});
response.write('404 Not Found\n');
response.end();
return;
}
//Do not send Content type, browser will pick it up.
response.writeHead(200);
var fileStream = fs.createReadStream(filename);
fileStream.on('end', function() {
response.end();
});
fileStream.pipe(response);
return;
});
}
exports.handleStatic = handleStatic;

fs.createReadStream would create a stream for the file. Instead of reading the entire file into memory and serving to the client, streaming is always better for performance.
In case you are creating your own version using the above code, do not forget to include response.end and a return statement.
For the dynamic part, I have also sent request object to the methods, this would enable them to read request parameters and relevant details to your dynamic code and thus help in generating dynamic data. You can return anything from the functions to your index.js page. It can be JSON as well, I am currently pushing HTML data back to the client.

var url = require("url");
function fetch(req) {
console.log("Request handler 'fetch' was called.");
return read(req);
}
function save(req) {
console.log("Request handler 'Save' was called.");
return read(req);
}
exports.fetch = fetch;
exports.save = save;
function read(req)
{
var content = "";
var _url = url.parse(req.url, true);
var pathname = _url.pathname;
console.log("Request for " + pathname + " received.");
if(_url.query)
{
content += "
Ohh! You have also provided me below data -</pre>
<ul>
<ul>";</ul>
</ul>
&nbsp;
<ul>
<ul>for(i in _url.query)</ul>
</ul>
&nbsp;
<ul>
<ul>{</ul>
</ul>
&nbsp;
<ul>
<ul>content += "
	<li>" + i + " = " + _url.query[i]  +"</li>
</ul>
</ul>
&nbsp;
<ul>
<ul>";</ul>
</ul>
&nbsp;
<ul>
<ul>}</ul>
</ul>
&nbsp;
<ul>content += "</ul>
<pre>
";
}
return content;
}

This would enable server to serve request by save and fetch methods. Now last but not least, our index.js file or the server loader.

var server = require('./server');
var controller = require("./controller");
var urlResponseHandlers = require("./urlResponseHandlers");
var handle = {};
handle["/"] = urlResponseHandlers.fetch;
handle["/fetch"] = urlResponseHandlers.fetch;
handle["/save"] = urlResponseHandlers.save;
server.start(controller.dispatch, handle);

Above we are simply mapping URL patterns to our functions we had defined above. Thus request for /fetch would be served by our fetch method while, save would server /save URL.
Now we just need a controller to map the URL patterns to the designated functions –

function dispatch(handler, pathname, req) {
console.log("About to dispatch a request for " + pathname);
var content = "Hey "+pathname;
if (typeof handler[pathname] === 'function') {
content += handler[pathname](req);
} else {
console.log("No request handler found for " + pathname);
}
return content;
}
exports.dispatch = dispatch;

That’s it, we now have built a fully functional static + dynamic Node server, it can serve both files from your drive as well as dynamic URLs.
Now just start your server

node index.js

Here is an output from my laptop ->
Static Page pipe’d from the server
Static page
Dynamic Content generated reading request
Dynamic Content
As usual, everything can be downloaded from Node JS Server.
PS: I am amazed by the speed Node serves you the content. Too Fast !! 🙂
Update : Updated the server to avoid dependencies of having a path for static files. View the post here.

12 thoughts on “Fully Functional NodeJS static + Dynamic Server

  1. I do agree with all of the concepts you have presented for your post. They’re really convincing and can definitely work. Still, the posts are very brief for newbies. May you please prolong them a little from subsequent time? Thank you for the post.

  2. Its like you read my thoughts! You seem to know a lot approximately this, like you wrote the guide in it or something. I feel that you just could do with some p.c. to pressure the message home a little bit, but instead of that, this is wonderful blog. A great read. I’ll definitely be back.

  3. whoah this weblog is excellent i love reading your posts. Keep up the good work! You realize, many persons are hunting around for this info, you could aid them greatly.

  4. Valuable info. Fortunate me I discovered your web site by accident, and I am shocked why this twist of fate didn’t came about in advance! I bookmarked it.

  5. In these circumstances, has been expected, but the small courtyard of the people have changed, or so unhappy in his mind, a bit lostGrandmother room, there are a few books’s a The battle for a few minutes, the piece of tens of meters long ridges, small devils who became impassable valley of deathll show me yours post.

  6. Sweet blog! I found it while browsing on Yahoo News. Do you have any tips on how to get listed in Yahoo News? I’ve been trying for a while but I never seem to get there! Thank you

Leave a Reply

Your email address will not be published. Required fields are marked *