Static middleware is probably among the most common type of middleware you will use
during the development of web applications with Node.
Mounting
Connect allows middleware to be mounted to specific URLs. For middleware like static,
this can be really useful because it allows you to map an arbitrary URL to any directory in your filesystem.
For example, assume you want to serve a directory called /images when the URL /my- images is requested. You can do it with mounting:
128
PA R T I I I • Web DevelopmentmaxAge
The static middleware takes an option called maxAge that specifies how long a certain
resource can be cached in the client’s user agent. This capability is useful when you know a certain asset is not going to change, and you don’t want the user’s browser to re-request it. For example, it’s common practice for web applications to bundle up all the client-side JavaScript into a file that represents a revision number. You can add the maxAge option to
ensure those get cached forever:
server.use(‘/js’, connect.static(‘/path/to/bundles’, { maxAge: 10000000000000 });
hidden
The other option static takes is hidden. If this option is set to true, Connect serves files
that begin with a dot (.) and are considered hidden in Unix filesystems:
server.use(connect.static(‘/path/to/resources’, { hidden: true });
QUERY
Sometimes in your applications you have optional data associated with a URL that you send as part of the query string.
For example, consider the url/blog-posts?page=5. If you point your browser to that
URL, then Node populates req.url with a string:
server.use(function (req) {
// req.url == “/blog-posts?page=5” });
Most likely, though, you actually want to access the value contained in that querystring. If you implement the query middleware, you get a req.query object automatically with
those values:
server.use(connect.query); server.use(function (req, res) { // req.query.page == “5” });
Again, parsing the query string is a common task for applications that Connect greatly simplifies. Just as in the static example where you stopped including the require call for
the fs module, you no longer need to worry about using the querystring module.
This middleware is included automatically for you in Express, the web framework subject of the next chapter. Another very useful middleware is logger, which is described next.
C H A P T E R 8 • Connect
129
LOGGER
The logger middleware is a useful diagnostics tool for your web application. It prints out
information about incoming requests and outgoing responses to the terminal. There are different built-in logging formats you can use
◾ default ◾ dev ◾ short ◾ tiny
For example, in order to leverage the dev logger format you would initialize the logger
middleware as follows:
server.use(connect.logger(‘dev’));
Consider the following example, a typical “Hello World” HTTP server with the logger middleware in use:
var connect = require(‘connect’); connect.createServer(
connect.logger(‘dev’) , function (req, res) { res.writeHead(200); res.end(‘Hello world’); }
).listen(3000);
Notice that I passed a series of middleware functions as parameters to the createServer
helper function. This is equivalent to initializing a Connect server and calling use twice.
When you go to http://127.0.0.1:3000 in your browser, you’ll notice two lines get
output:
GET / 200 0ms
GET /favicon.ico 200 2ms
The browser is requesting /favicon.ico and /, and the connect logger is displaying the
method for the request, in addition to the response status code, and how long the process took.
dev is a concise and short logging format, giving you insight into behavior and performance
while you’re testing out your web apps.
130
PA R T I I I • Web DevelopmentSay you want to log only the method and the IP:
server.use(connect.logger(‘:method :remote-addr’));
You can also log headers by using the dynamic tokens req and res. To log the content- length and the content-type of the response along with how long it took to produce,
you use the following:
server.use(connect.logger(‘type is :res[content-type], length is ‘ + ‘:res[content-length] and it took :response-time ms.’));
Note: Remember that, in Node, request/response headers are always lowercase.
If you apply it to the original website that requests four images, you can see some interesting output, as shown in Figure 8-6. (Make sure you request on a fresh cache and clear your browser data prior to running the example.)
Figure 8-6: Your custom logger in action
Following is the complete list of tokens you can use:
◾ :req[header] (for example, :req[Accept])
◾ :res[header] (for example, :res[Content-Length]) ◾ :http-version ◾ :response-time ◾ :remote-addr ◾ :date ◾ :method ◾ :url ◾ :referrer ◾ :user-agent ◾ :status
C H A P T E R 8 • Connect
131
You can also define custom tokens. Say you want a shortcut called :type that refers to the Content-Type of the request; in that case, you use the following:
connect.logger.token(‘type’, function (req, res) { return req.headers[‘content-type’];
});
The next middleware to consider is body parser, which automates another task you’ve been manually writing for http servers so far.