You have your web server, but now you need to be able to send information from the server in the form of a response.
Solution
A server response is a Node.js EventEmitter object that is emitted as part of the request event. In this solution you will utilize the response object to directly write the content to the requester. First, you want to send an HTML document. You can do this by creating a response and sending the HTML content directly.
Listing 4-11. Response.write of HTML /**
* Sending a response from your server */
var http = require('http');
var server = http.createServer(function(req, res) { res.setHeader('Content-Type', 'text/html');
Chapter 4 ■ Building a WeB Server res.write('<html>'); res.write('<head><meta charset="utf-8"></head>'); res.write('<body>'); res.write('<h2>Hello World</h2>'); res.write('</body></html>'); res.end(); }); server.listen(8080);
You are now serving HTML content directly in your response. You may need to be able to send other types of content to provide the robust solution for your application. In this case you choose to send a JavaScript Object Notation (JSON)-encoded object so the client can retrieve information from your server. This is similar in implementation with a few minor changes that you will see in detail in the How It Works section.
Listing 4-12. A JSON serverResponse var http = require('http');
var server = http.createServer(function(req, res) { res.setHeader('Content-Type', 'application/json'); res.writeHead(200, 'json content');
res.write('{ "wizard": "mithrandir" }'); res.end();
});
server.listen(8080);
How It Works
You now are serving content from your web server by using the serverResponse object. This object, as utilized in this solution, carries with it some valuable functions. The first line within the requestListener callback is response.setHeader. The setHeader function does exactly what the name implies; it sets the headers for the response. These are set in a name and value pairing, res.setHeader(‘Name’, ‘Value’);.
In the solutions, you set the Content-Type header to define the type of content that was being sent with your request. You can also set cookies, custom header parameters, or anything that would accompany a request header from your server.
The other method that is utilized in this solution to set the response headers is the response.writeHead method. This method does not limit your header creation to a single name and value pair. This method takes up to three arguments. The first argument, which is required, sets the HTTP status code for the response. You then have the option to set a custom description, or reason phrase, that corresponds to the status code description. This can be any reason phrase you wish, departing from the HTTP standard descriptions.
Listing 4-13. HTTP Reason Phrase Override in Node.js if (typeof arguments[1] == 'string') {
reasonPhrase = arguments[1]; headerIndex = 2;
} else {
reasonPhrase = STATUS_CODES[statusCode] || 'unknown'; headerIndex = 1;
Chapter 4 ■ Building a WeB Server
The third parameter is actually a header object that will take the name and value pairs, not just individual name-value pairs, as an entire object. To refactor the solution for the JSON serverResponse above, you could simply make one call to response.writeHead to get the same result.
Listing 4-14. Combining HTTP Status Code, Reason Phrase, and Headers in a response.writeHead Call res.writeHead(200, ‘json content’, {
‘Content-Type’: ‘application/json’});
You then send a body of your response to the client by using response.write. This function will take a string that represents a chunk of the response body. The second parameter of response.write is to set the encoding of the response, which defaults to utf8. The response.write does not require that you have already set the header via the previously mentioned methods. If the header is not explicitly set, the response.write method will implicitly define the header with a status code of 200. The write method then ensures that the headers have been sent. If the headers have not been sent, then they are sent along with the initial write of the data to the client.
Listing 4-15. If Headers Aren’t Already Sent, Send Them with the First Chunk if (!this._headerSent) {
if (typeof data === 'string') { data = this._header + data; } else { this.output.unshift(this._header); this.outputEncodings.unshift('ascii'); } this._headerSent = true; }
return this._writeRaw(data, encoding);
You now have seen and executed the methods for sending a response from your web server. These options are just a subset of what is possible with HTTP responses. The full list of what is available for use is shown in Table 4-1. Table 4-1. HTTP serverResponse Methods
Method
Description
response.addTrailers(headers) Adds HTTP trailing headers (a header but at the end of the message) to the response.
Trailers will only be emitted if chunked encoding is used for the response; if it is not (e.g., if the request was HTTP/1.0), they will be silently discarded.
response.end([data], [encoding]) Signals to the server that all of the response headers and body have been sent; the server should consider the message complete. The method, response.end(), must be called on each response.
response.getHeader(name) Reads out a header that's already been queued but not sent to
the client. Note that the name is case-insensitive. This can only be called before headers get implicitly flushed.
Chapter 4 ■ Building a WeB Server
Method
Description
response.headersSent Boolean (read-only). It is true if headers were sent,
but false otherwise.
response.removeHeader(name) Removes a header that's queued for implicit sending.
response.sendDate When true, the Date header will be automatically generated
and sent in the response if it is not already present in the headers. Defaults to true.
response.setHeader(name, value) Sets a single header value for implicit headers. If this header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings here if you need to send multiple headers with the same name.
response.setTimeout(milliseconds, callback) Sets the socket's timeout value to milliseconds. If a callback is provided, then it is added as a listener on the 'timeout' event on the response object.
response.statusCode When using implicit headers (not calling response.writeHead()
explicitly), this property controls the status code that will be sent to the client when the headers get flushed.
response.write(chunk, [encoding]) Sends a chunk of the response body. This method
may be called multiple times to provide successive parts of the body.
writeContinue() Sends an HTTP/1.1 100 Continue message to the client,
indicating that the request body should be sent. writeHead(statusCode, [reasonPhrase],
[headers])
Sends the response header to the request. Table 4-1. (continued)