Node by example

Node by example: 8. HTTP module

8. HTTP module

The complete source code can be downloaded here: http://github.com/Hendrik/node-by-example

Node provides a module specifically for the http protocol. Use it via require('http').

As taken from the official documentation at http://nodejs.org/api.html#http-145:
The HTTP interfaces in Node are designed to support many features of the protocol which have been traditionally difficult to use. In particular, large, possibly chunk-encoded, messages. The interface is careful to never buffer entire requests or responses, the user is able to stream data.

In order to support the full spectrum of possible HTTP applications, Node's HTTP API is very low-level. It deals with stream handling and message parsing only. It parses a message into headers and body but it does not parse the actual headers or the body.

A simple HTTP server & client example, where the server provides an index page with argument support and a 404 page for any other requests.

Let's start with the server:
See 08_http/simple_server.js:

var     sys = require("sys"),
       http = require("http"),
        url = require("url"),
querystring = require("querystring");

http.createServer(function (request, response) {
  switch (url.parse(request.url).pathname) {
    case '/':
      show_index(request, response);
      break;
    default:
      show_404(request, response);
      break;
  }
}).listen(8000);

function show_index(request, response) {
  sys.puts("Serving index page");
  response.writeHead(200, {'Content-Type': 'text/html'});
  var output = 'node.js HTTP server exampleIndex output';
  var url_request = url.parse(request.url).query;
  output += "

Request query: " + url_request + "

"; if (url_request) sys.puts("Request query: " + JSON.stringify(querystring.parse(url_request))); output += ''; response.write(output); response.end(); } function show_404(request, response) { sys.puts("Serving 404 error page"); response.writeHead(404, {'Content-Type': 'text/plain'}); response.write('404 - Please try again.'); response.end(); }

 

The server will parse the requested URL for the requested pathname and its query string, which can be done by using the "url" and "querystring" modules (more on those later):

url = require("url"),
querystring = require("querystring");

 

First we create the HTTP server object, where request is an instance of http.ServerRequest, which contains details such as the requested URL, and response is an instance of http.ServerResponse, which is used to send a response to the client:

http.createServer(function (request, response) {
  ...
}).listen(8000);

 

The server can provide 2 different pages, the index page and a 404 page for all other requests.
As mentioned above the "request" object holds the url, but since we only want to know the requested page, we can use the url.parse().pathname function to get the requested page from the "request" object.
Requests for the index ('/') page will call the show_index() function, whereas any other request calls the show_404() function.

switch (url.parse(request.url).pathname) {
  case '/':
    show_index(request, response);
    break;
  default:
    show_404(request, response);
    break;
}

 

The index page displays a simple html document, including the requested query string.
First you need to server the header to the client:

function show_index(request, response) {
  sys.puts("Serving index page");
  response.writeHead(200, {'Content-Type': 'text/html'});
  ...
}

 

Then we prepare the output and extract the query from the request URL:
e.g.: http://127.0.0.1:8000/?test_arg=some_value would display "Request query: test_arg=some_value".

var output = 'node.js HTTP server exampleIndex output';
var url_request = url.parse(request.url).query;
output += "

Request query: " + url_request + "

";

 

Here comes the querystring sample, which deserialzies the url_request object making it easier to process the individual query arguments.
e.g.: http://127.0.0.1:8000/?test_arg=some_value would result in "Request query:

{"test_arg":"some_value"}"
if (url_request) sys.puts("Request query: " + JSON.stringify(querystring.parse(url_request)));
output += '';

 

Once the output has been prepared we can send it to the client and signal to the server that all of the response headers and body have been sent. The method response.end() *must* be called on each response!:

response.write(output);
response.end();

 

The 404 page simply sends to 404 header to the client and displays a short message:

function show_404(request, response) {
  sys.puts("Serving 404 error page");
  response.writeHead(404, {'Content-Type': 'text/plain'});
  response.write('404 - Please try again.');
  response.end();
}

 

Now lets take a look at a sample HTTP client, which connects to this server with a query argument and displays the returned content:
See 08_http/simple_client.js:

var sys = require("sys"),
   http = require("http");

var client = http.createClient(8000, "127.0.0.1");
var request = client.request("GET", "/?query_arg=testing", {"host": "127.0.0.1"});

sys.puts("Connecting to http://127.0.0.1:8000/?query_arg=testing");

request.addListener("response", function(response) {
  sys.puts("STATUS: " + response.statusCode);
  sys.puts("HEADERS: " + JSON.stringify(response.headers));
  response.setBodyEncoding("UTF8");
  response.addListener("data", function(chunk) {
    sys.puts("BODY: " + chunk);
  });
  response.addListener("end", function() {
    sys.puts("End of response");
  });
});
request.end();

 

The output will be something like:

Connecting to http://127.0.0.1:8000/?query_arg=testing
STATUS: 200
HEADERS: {"content-type":"text/html","connection":"close","transfer-encoding":"chunked"}
BODY: node.js HTTP server exampleIndex output

Request query: query_arg=testing

End of response

 

First we create the HTTP client and request objects, where the client contains the port and host you want to connect to and the request contains the method, path and host to connect to:

var client = http.createClient(8000, "127.0.0.1");
var request = client.request("GET", "/?query_arg=testing", {"host": "127.0.0.1"});

 

The request object's "response" event will emit when a response is received from the server. This event is emitted only once.
In this case we use it to display the returned status code, headers and set the encoding type of the response:

request.addListener("response", function(response) {
  sys.puts("STATUS: " + response.statusCode);
  sys.puts("HEADERS: " + JSON.stringify(response.headers));
  response.setBodyEncoding("UTF8");
  ...
}

 

The "data" event emits whenever data is received from the server:

response.addListener("data", function(chunk) {
  sys.puts("BODY: " + chunk);
});

 

The "end" event also emits exactly once per message and after it emitted no other events will be emitted on the response.

response.addListener("end", function() {
  sys.puts("End of response");
});

 

To finish sending the request use:

request.end();

 

These examples only scratched the surface of the available features in the HTTP module. For more advanced features and whole frameworks built around the http module, please see the node modules page: http://wiki.github.com/ry/node/modules