Serving files

We can see that it's not very intuitive or easy to write HTML pages with our current infrastructure. Writing the HTML in the JS code as strings is not fun. We would like to serve the HTML content from the HTML files. We will begin with taking in two modules, which we will need to read from a file (on the disk) in our app module:

var path = require('path'),
var fs = require('fs'),

The first one, path, is the module we use to work with paths, and fs is the module used to interact with the filesystem. The next step is to get the path to the application's root.

var root = __dirname;

__dirname is a variable managed by Node.js and has the absolute path to the directory of the Node.js application script. Now, we add the method that will be doing the heavy work of reading the file and sending it to the browser. Add this method to app.js:

var serveStatic = function(response, file){
  var fileToServe = path.join(root, file);
  var stream = fs.createReadStream(fileToServe);

  stream.on('data', function(chunk){
    response.write(chunk);
  });

  stream.on('end', function(){
    response.end();
  });
}

The serveStatic method that we have created accepts two arguments, the HTTP response object and the file path to serve.

  var fileToServe = path.join(root, file);

We append the file path to our root path to build the absolute path of the file to serve. Here we are implicitly assuming that all the files to be served are relative to the Node.js application root; this will prevent a file outside the application from being served by mistake. Node.js handles I/O as streams. We can see that this is similar to the way it handles the incoming POST data.

  var stream = fs.createReadStream(fileToServe);

We use createReadStream from the fs module to create a stream that reads from the file. This stream again demonstrates the non-blocking, asynchronous, and event-driven approach of Node.js.

 stream.on('data', function(chunk){
    response.write(chunk);
  });

The stream works as an event emitter, triggering the 'data' event when there is new data on the stream. This allows the application to continue with the other processing activities, without having to wait for the data to be read. What we are doing here is, we are writing the data we receive on every read to the response stream.

  stream.on('end', function(){
    response.end();
  });

Once all the data from the file is read and the stream gets an EOF, it will trigger the 'end' event. We will call end on our response as well. Finally, we will modify the GET handler "/echo" to serve from a file called echo.html, and write the content of the HTML to be served to that file.

server.forRoute("GET", "/echo", function(request, response){
    serveStatic(response, "echo.html");
});

We have removed all the code to build the response string, replacing it with a call to serveStatic to serve echo.html.

<html>
  <head>
    <title>Node.js Echo</title>
  </head>
  <body>
    <form method="POST">
      <input type="text" name="msg"/>
      <input type="submit" value="echo"/>
    </form>
  </body>
</html>

The content that we were previously building as a string is now written to this file. Once we make these changes and run app.js with Node.js, you should be able to see the form on http://localhost:9999/echo retaining its original functionality.

Those familiar with Unix-like operating systems will realize that the functionality we just implemented to read from one stream and write to another can also implemented by using pipes (|). It shouldn't come as a surprise that Node.js provides a high-level function to do exactly the same.

Using the pipe method provided on stream in Node, we can modify the serveStatic method as follows:

var serveStatic = function(response, file){
  var fileToServe = path.join(root, file);
  var stream = fs.createReadStream(fileToServe);
  stream.pipe(response);
}

Here we are replacing the data and end event handlers using stream.pipe(response).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset