Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
3688 lines (3285 sloc) 243 KB
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The Node Beginner Book » A comprehensive Node.js tutorial</title>
<meta name="description" content="Um tutorial compreensivo de Node.js para iniciantes: Aprender como construir uma aplicação web compreta com JavaScript no lado do servidor." />
<link rel="icon" href="favicon.png" type="image/png" />
<link rel="stylesheet" type="text/css" href="default.css" />
</head>
<body>
<div id="forkmeongithub">
<a href="https://github.com/ManuelKiessling/NodeBeginnerBook"><img src="fork_me_on_github.png" width="149" height="149" alt="Fork me on GitHub" /></a>
</div>
<div id="ibookstore-banner">
<a href="buy-ibook/index.html"><img src="ibookstore-banner.jpg" width="100%" /></a>
</div>
<div id="translations">
<table>
<tr>
<td>
<a href="index-jp.html">
<div class="flag"><img src="jp-flag.png" width="24" height="24" alt="japanese flag" /></div>
<div class="text">日本語で読む</div>
</a>
</td>
<td>
<a href="index-es.html">
<div class="flag"><img src="es-flag.png" width="24" height="24" alt="spanish flag" /></div>
<div class="text">Lee este tutorial en Español</div>
</a>
</td>
<td>
<a href="index-kr.html">
<div class="flag"><img src="kr-flag.png" width="24" height="24" alt="korean flag" /></div>
<div class="text">이 튜토리얼을 한글로 보세요</div>
</a>
</td>
</tr>
<tr>
<td>
<a href="index-zh-cn.html">
<div class="flag"><img src="cn-flag.png" width="24" height="24" alt="chinese flag" /></div>
<div class="text">阅读本书中文版</div>
</a>
</td>
<td>
<a href="index-zh-tw.html">
<div class="flag"><img src="cn-flag.png" width="24" height="24" alt="chinese flag" /></div>
<div class="text">阅读本书繁体中文版</div>
</a>
</td>
<td>
<a href="http://www.nodebeginner.ru">
<div class="flag"><img src="ru-flag.png" width="24" height="24" alt="russian flag" /></div>
<div class="text">Читать этот учебник на русском</div>
</a>
</td>
<td>
<a href="index-pt-br.html">
<div class="flag"><img src="pt-br-flag.png" width="24" height="24" alt="brazilian flag" /></div>
<div class="text">Leia este tutorial em portugês.</div>
</a>
</td>
</tr>
</table>
</div>
<div class="buybox">
<div class="buy-the-bundle">
<div class="cover">
<p>
A perfeita introdução mais a referência perfeita em um só pacote!
</p>
<a href="buy-bundle/index.html"><img src="the_node_beginner_book_cover_small.png" height="86" width="57" /></a>
<a href="buy-bundle/index.html"><img src="hands-on_node.js_cover.png" height="86" width="57" /></a>
</div>
<div class="description">
<p>
LeanBundle currently offers
the final version of
<br />
<strong>The Node Beginner Book</strong>
<br />
plus Pedro Teixeira's excellent
<br />
<strong>Hands-on Node.js</strong> for only
<br />
<br />
<strong class="price dollarsign">$</strong><strong class="price">9.99</strong>
<br />
(regular price <del>$21.98</del>)
</p>
</div>
<div class="buy">
<p>
226 pages in total
<br />
PDF, ePub & MOBI
<br />
Direct download
<br />
Free updates
</p>
<a class="buttonlink" href="buy-bundle/index.html">
<div class="button">Buy this<br />bundle now</div>
</a>
</div>
</div>
<div class="buy-kindle">
<div class="inner">
<a href="buy-kindle/index.html"><img class="cover" src="the_node_beginner_book_cover_small.png" height="86" width="57" /></a>
<br />
<a href="buy-kindle/reviews.html"><img class="stars" src="amazon_rating_stars.png" width="65" height="12" /></a>
<br />
(<a href="buy-kindle/reviews.html">Read customer reviews</a>)
<br />
<a href="buy-kindle/index.html"><img class="button" src="add_to_kindle_button.png" width="102" height="25"/></a>
</div>
</div>
</div>
<div id="book">
<div>
<h1>O livro para iniciantes em Node</h1>
<div id="author">Tutorial de Node.js por: <a href="http://twitter.com/manuelkiessling">Manuel Kiessling</a></div>
<div id="social">
<a href="https://twitter.com/share" class="twitter-share-button" data-url="http://www.nodebeginner.org" data-text="The Node Beginner Book » A comprehensive Node.js tutorial:" data-via="manuelkiessling">Tweet</a>
<br />
<g:plusone size="medium"></g:plusone>
</div>
<a name="about"></a>
<h2>Sobre</h2>
<p>
O objetivo deste documento é para te ajudar a começar a desenvolver aplicações com Node.js, ensinando à você tudo que voê precisa saber sobre JavaScript avançado ao longo do caminho. Aqui iremos muito mais adiante do que um simples tutorial com "Hello World".
</p>
<a name="status"></a>
<h3>Status</h3>
<p>
Você esta lento a versão final deste livro,
You are reading the final version of this book, em exemplo, as atualizações são unicas e exclusivas para corrigir erros ou para refletir mudanças das novas versões do Node.js. A última atualização foi em 12 de Fevereiro de 2012.
</p>
<p>
Os códigos de exemplos neste livro foram testados para funcionar com a versão 0.6.11 do Node.js.
</p>
<a name="intended-audience"></a>
<h3>Público alvo</h3>
<p>
Este documento irá provavelmente será melhor entendido por leitores que possuem uma história similar a minha: experiência com pelo menos uma linguagem orientada a objetos como Ruby, Python, PHP ou java, um pouco de experiência com JavaScript, e completamente principiante em Node.js.
</p>
<p>
Visa os desenvolvedores que possuem experiência com outras linguagens de programação, de modo que este documento não irá cobrir coisas básicas, como tipos de dados, variáveis, estruturas de controle e suas preferências. Você já precisa saber sobre estes conceitos para entender este documento.
</p>
<p>
Contudo, por causa das funções e objetos em JavaScript são diferentes de outras linguagens, iremos explicar em mais detalhes.
</p>
<a name="structure"></a>
<h3>Estrutura deste documento</h3>
<p>
Ao terminar este documento, você irá ter criado uma aplicação web completa que permite os usuários desta aplicação visualizar as paginas e fazer upload de arquivos.
</p>
<p>
O que, é claro, não é mudar o mundo exatamente, mas vamos ir à alguns quilômetros extras e não apenas criar o código "apenas o suficiente" para fazer os possíveis casos de uso, mas criar uma simples, ainda que simples um framework completo separando os diferentes aspectos da nossa aplicação.Você verá o que eu quero dizer em um minuto.
</p>
<p>
Vamos começar olhando como o desnevolvimento JavaScript é utilizado em Node.Js e é diferente do desenvolvimento JavaScript para os navegadores.
</p>
<p>
Em seguida, vamos ficar com a boa e velha tradição de escrever um "Hello World" na aplicação, que é a aplicação mais básica que Node.js pode fazer.
</p>
<p>
Então, iremos discutir o tipo de aplicações "reais" que queremos construir, dissecando as diferentes partes que devemos implementar para montar esta aplicação, e começar a trabalhar em cada uma dessas partes passo-a-passo.
</p>
<p>
Como prometido, ao longo do caminho nós iremos aprender sobre alguns e os mais avançados conceitos de JavaScript, como fazer uso dele, e olhar o porquê faz sentido usar estes conceitos ao invés daqueles que conhecemos de outras linguagens de programação.
</p>
<p>
O código fonte final desta aplicação está disponível através do
<a href="https://github.com/ManuelKiessling/NodeBeginnerBook/tree/master/code/application">Repositório GitHub,
NodeBeginnerBook</a>.
</p>
<div id="table-of-contents-headline">Índice analítico</div>
<div id="table-of-contents">
<ul>
<li><a href="#about">Sobre</a>
<ul>
<li><a href="#status">Status</a></li>
<li><a href="#intended-audience">Público alvo</a></li>
<li><a href="#structure">Estrutura deste documento</a></li>
</ul>
</li>
<li><a href="#javascript-and-nodejs">JavaScript e Node.js</a>
<ul>
<li><a href="#javascript-and-you">JavaScript e você</a></li>
<li><a href="#a-word-of-warning">Uma palavra de alerta</a></li>
<li><a href="#server-side-javascript"> JavaScript no lado do servidor</a></li>
<li><a href="#hello-world">"Olá Mundo"</a></li>
</ul>
</li>
<li><a href="#a-full-blown-web-application-with-nodejs">
Uma aplicação web completa exaustiva com Node.js</a>
<ul>
<li><a href="#the-use-cases">Os casos de uso</a></li>
<li><a href="#the-application-stack">A aplicação em pilha</a></li>
</ul>
</li>
<li><a href="#building-the-application-stack">Construindo a pilha de aplicativos</a>
<ul>
<li><a href="#a-basic-http-server">Um servidor HTTP básico</a></li>
<li><a href="#analyzing-our-http-server">Analisando nosso servidor HTTP</a></li>
<li><a href="#passing-functions-around">Passando em torno das funções</a></li>
<li><a href="#how-function-passing-makes-our-http-server-work">Qual função passada faz nosso servidor HTTP funcionar</a></li>
<li><a href="#event-driven-callbacks">Eventos dirigidos e callback assíncronos</a></li>
<li><a href="#how-our-server-handles-requests">Como nosso servidor processa as requisições</a></li>
<li><a href="#finding-a-place-for-our-server-module">Procurando um lugar para nosso módulo servidor</a>
</li>
<li><a href="#whats-needed-to-route-requests">O que é necessário para rotear nossas requisições?</a></li>
<li><a href="#execution-in-the-kongdom-of-verbs">Execução no reino dos verbos</a></li>
<li><a href="#routing-to-real-request-handlers">Roteamento para processamento de requições reais</a></li>
<li><a href="#making-the-request-handlers-respond">Fazendo os processos responderem as requisições</a>
<ul>
<li><a href="#how-to-not-do-it">Como não fazer isto.</a></li>
<li><a href="#blocking-and-non-blocking">Bloquando e não bloquendo</a></li>
<li><a href="#responding-request-handlers-with-non-blocking-operations">Respondendo requisições com operações não bloqueantes</a>
</li>
</ul>
</li>
<li><a href="#serving-something-useful">Servindo algo útil</a>
<ul>
<li><a href="#handling-post-requests">Manipulando requisições POST</a></li>
<li><a href="#handling-file-uploads">Manipulando uploads de arquivos</a></li>
</ul>
</li>
<li><a href="#conclusion-and-outlook">Conclusões e perspectivas</a></li>
</ul>
</li>
</ul>
</div>
<a name="javascript-and-nodejs"></a>
<h2>JavaScript e Node.js</h2>
<a name="javascript-and-you"></a>
<h3>JavaScript e Você</h3>
<p>
Antes de falarmos sobre todo o material técnico, vamos dar uma pausa e falr sobre você e sua familiaridade com o JavaScript. Este capítulo está aqui para que você possa estimar se a leitura deste documento ou qualquer outra faz sentido para você.
</p>
<p>
Se você é como eu, voc~e come~çou com desenvolvimento HTML à um tempo atrás, escrevendo documentos em HTML. Ao longo disto você observou uma coisa engraçada chamada JavaScript, mas você usava somente o JavaScript em formas bem básicas, adicionando interatividade, de vez em quando, para suas páginas web.
</p>
<p>
O quê você realmente queria era "uma coisa mais real", você queria saber como contruir web sites complexos - então, você aprendeu uma linguagem de programação como PHP, PHP, Ruby, Java, e começou a escrever seus códigos "backend".
</p>
<p>
Porém, você manteve um olho no JavaScript,você viu que com a introdução do jQuery, Prototype e outras bibliotecas afins, as coisas ficaram mais avançadas na terra/mundo do JavaScript, e que esta linguagem realmente é muito mais do que um simples<em>window.open()</em>.
</p>
<p>
Entretanto, isto tudo ficava no frontend -(lado do cliente)-, e embora fosse legal ter o jQuery à sua disposição sempre que você sentiu necessidade de apimentar uma página , no final do dia você era, na melhor das hipóteses, um <em>Usuário</em> JavaScript , mas não um <em>desenvolvedor</em>JavaScript.
</p>
<p>
E então veio o Node.js. JavaScript no lado do servidor, o quão legal é isto?
</p>
<p>
Você decidiu que é hora de sair do antigo, para o novo JavaScript. Mas espere, escrever aplicações Node.Js é uma coisa; entender o por que eles são escritos da forma como eles são escritos significa - compreender o JavaScript. understanding why they need to be written the
way they are written means - understanding JavaScript. E desta vez é para valer!
</p>
<p>
Aqui esta o problema:
Por que o JavaScript realmente possui duas vidas, talvez até três vidas ( o ajudante pouco engraçado DHTML de meados da década de 90, a mais séria biblioteca frontend como jQuery e afins, e agora JavaScript no lado do servidor), não é assim tão fácil encontrar informação que te ajude a aprender JavaScript "da maneira correta", de modo que para escrever aplicações em Node.js, você irá sentir que não está somente usando JavaScript, você esta desenvolvendo-o.
</p>
<p>
Porque este é o problema:
Você é um desenvolver experiente, e não quer aprender novas técnicas para apenas Hackear por ai e usar isto; Você quer ter certeza de que se esta aproximando da maneira correta.
</p>
<p>
Ha, é claro, uma excelente documentação lá fora. Mas somente a documentação as vezes não é suficiente. O que precisa-se, é, orientação.
</p>
<p>
Meu objetivo é fornecer um guia para você.
</p>
<a name="a-word-of-warning"></a>
<h3>Uma palavra de alerta</h3>
<p>
Existem muitas pessoas realmente boas em JavaScript lá fora. Eu não sou um deles.
</p>
<p>
Eu sou apenas o cara que estava falando no paragráfo anterior. Eu sei uma coisa ou duas sobre desenvolvimento backend em aplicações web, I know a thing or two about developing backend
web applications, mas eu ainda sou novo para o "verdadeiro" JavaScript e novo em Node.Js ainda. Eu aprendi alguns aspectos avançados do JavaScript recentemente. Não sou experiente.
</p>
<p>
É por isso que este livro não é algo como "do inicante ao expert". É mais como "do inicante ao iniciante avançado".
</p>
<p>
Se eu não falhar, então, este será o tipo de documento que eu gostaria de ter para quando começar a utilizar Node.js.
</p>
<a name="server-side-javascript"></a>
<h3>JavaScript no lado do servidor</h3>
<p>
As primeiras encarnações do javaScipt viveu em navegadores. Mas isso é apenas um contexto. Ele define o que você pode fazer com a linguagem, mas não diz muito sobre o que a linguagem, em si, pode fazer. JavaScript é uma linguagem "completa":
você pode usar em vários contextos e conseguir fazer tudo com ele assim como em qualquer outras linguagens "completas".
</p>
<p>
Node.js é realmente um outro contexto: te permitindo rodar o código JavaScript no backend, fora dos navegadores.
</p>
<p>
A fim de executar o JavaScript, com a intenção de executar em backend, é necessário que ela seja interpretada e, então, executada. Isto é o que o Node.js faz, por meio da utilização do Google's V8 VM, o mesmo ambiente de execução para JavaScript que o Google
Chrome usa.
</p>
<p>
Além disso, o Node.js carrega um monte de módulos úteis, para que você não tenha que escrever tudo do zero, como por exemplo, algo como gerar a saida de strings no console.
</p>
<p>
Assim, o Node.js são duas coisas: um ambiente de execução e uma biblioteca.
</p>
<p>
Com o intuito de fazer uso destes recursos, voce precisa instalar o Node.js. Ao invés de repetir o processo de instalação aqui, pedimos que você visite
<a href="https://github.com/joyent/node/wiki/Installation" title="Building and Installing Node.js">o guia oficial de instalação</a>. Por favor, volte quando estiver tudo funcionando.
</p>
<a name="hello-world"></a>
<h3>"Olá Mundo"</h3>
<p>
Ok, vamos pular na água gelada e escrever nossa primeira aplicação em Node.js: "Olá mundo".
</p>
<p>
Abra seu editor favorito e crie o arquivo chamado
<em>helloworld.js</em>. Queremos que ele escreva "Olá Mundo"
para STDOUT, e aqui esta o código necessário para isto:
</p>
<pre class="prettyprint lang-js"><span class="pln">console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span></pre>
<p>
Salve o arquivo, e execute através do Node.js:
</p>
<pre>node helloworld.js</pre>
<p>
Esta deverá ser a saída <em>Hello World</em> em seu terminal.
</p>
<p>
OKs, isto é chato, certo? Vamos escrever alguns casos reais.
</p>
<a name="a-full-blown-web-application-with-nodejs"></a>
<h2>Uma aplicação web completa e exaustiva com Node.js</h2>
<a name="the-use-cases"></a>
<h3>Caso de uso</h3>
<p>
Vamos deixa-lo simple, porém realista:
</p>
<ul>
<li>
O usuário deverá ser capaz de usar nossa aplicação em um navegador web
</li>
<li>
O usuário deverá ver uma página de boas vindas quando acessar http://<em>domain</em>/start que ira exibir um formulário de upload de arquivos
</li>
<li>
Ao escolher uma imagem para fazer upload e submeter o formulário, esta imagem deverá então ser salva em
http://<em>domain</em>/upload, onde irá ser exibida uma vez que o upload foi terminado
</li>
</ul>
<p>
Pois bem. Agora, você pode atingir este passo/objetivo pelo google e hackeando <em>alguma coisa</em>. Mas isso não é o que queremos fazer aqui.
</p>
<p>
Além disso, nós não queremos escrever somente o código mais básico para atingir nosso objetivo, entretanto, fazer o código mais correto e elegante possível. Intencionalmente, nós iremos adicionar mais abstração do que o necessário afim de obter um feedback maior, para construir mais aplicações complexas com Node.js.
</p>
<a name="the-application-stack"></a>
<h3>A aplicação em pilha</h3>
<p>
Vamos dissecar nossa aplicação.
Let's dissect our application. Quais partes precisam estar implementadas a fim de cumprir os casos de uso?
</p>
<ul>
<li>
Nós queremos servir páginas web, portanto precisamos de um
<strong>HTTP servidor</strong>
</li>
<li>
Nosso servidor precisará de responder diferentes requisições, dependendo de qual URL foi chamado do pedido feito, portanto, precisamos de algum tipo de
<strong>roteamento</strong> a fim de mapear as requisições pelo que foi solicitado.
</li>
<li>
Para tratar as requisições que chegam ao servidor e que foram encaminhadas usando o roteamento, precisamos de um <strong>manipulador de solicitação </strong> real.
</li>
<li>
O roteador provavelmente deverá tratar, também, qualquer chegada de dados do tipo POST e entregar ao manipulador de requisição de uma forma conveniente, portanto, precisamos de um <strong>manipulador de dados</strong>
</li>
<li>
Nós não queremos somente processar os pedidos das URLs, nós também precisaremos exibir o conteudo quando estas URLs serão chamadas, o qie significa que vamos precisar de um tipo de
<strong>visão lógica</strong> que os manipuladores de requisição podem usar afim de setar/enviar o conteudo para o navegador do usuário.
</li>
<li>
Por último, mas não menos importante, o usuário será capaz de fazer upload das imagens, então precisamos de algum tipo de
<strong>upload handling</strong> que cuida destes detalhes
</li>
</ul>
<p>
Vamos pensar um momento em como nós íriamos construir esta pilha com PHP. Não é segredo nenhum que a configuração típica seria um servidor HTTP rodando Apache com o mod_php5 instalado.
<br>
O que significa que:"nós precisamos ser capazes de servir páginas web e receber solicitações HTTP", mas isso nao acontence dentro do PHP.
</p>
<p>
Bem, com Node.js, as coisas são diferentes. Porque com Node.js, nós nao vamos somente implementar nossa aplicação, vamos também implementar nosso servidor HTTP por completo. Na verdade, mossa aplicação web e nosso servidor são basicamente os mesmos.
</p>
<p>
Isto pode soar como trabalhoso, mas vamos ver em um momento que com Node.js não é assim.
</p>
<p>
Vamos começar no início e implementar a primeira parte de nossa pilha, o servidor HTTP.
</p>
<a name="building-the-application-stack"></a>
<h2>Construindo a pilha de aplicativos</h2>
<a name="a-basic-http-server"></a>
<h3>Um servidor HTTP básico</h3>
<p>
Quando cheguei ao ponto onde eu queria começar com minha primeira
aplicação em Node.js, eu me perguntava não somente em como codificar,
mas também em como organizar meu código.
<br>
Eu preciso colocar tudo em um arquivo? Muitos tutoriais na web
que ensinam, como escrever um servidor HTTP básico em Node.js
colocam toda a lógica em um lugar. E se eu quiser ter certeza que
meu código continuará legível se eu implementar mais coisas?
</p>
<p>
Acontece que, é relativamente fácil manter essas preocupações
separando o seu código, colocando-os em módulos.
</p>
<p>
Isto te permite em ter um arquivo principal legivel/limpo,
This allows you to have a clean main file, que você executa
com Node.js, e módulos legíveis que podem ser usados pelo
arquivo principal ou entre os outros módulos.
</p>
<p>
Então, vamos criar um arquivo principal que nós usaremos para
começar nossa aplicação, e um módulo onde nosso código do
servidor HTTP irá ficar.
</p>
<p>
Minha impressão é que, é mais ou menos, um padrão para
nomear seu arquivo principal <em>index.js</em>. Faz mais sentido colocar
nosso módulo de servidor com o nome <em>server.js</em>.
</p>
<p>
Vamos comecar com nosso módulo para o servidor HTTP. Crie um arquivo
<em>server.js</em> na raíz do diretório do nosso projeto,
e preencha-o seguindo o código abaixo:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br>http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">(</span><span class="kwd">function</span><span
class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; response</span><span
class="pun">.</span><span class="pln">writeHead</span><span class="pun">(</span><span
class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span
class="pun">{</span><span class="str">"Content-Type"</span><span class="pun">:</span><span
class="pln"> </span><span class="str">"text/plain"</span><span class="pun">});</span><span
class="pln"><br>&nbsp; response</span><span class="pun">.</span><span class="pln">write</span><span
class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span><span
class="pln"><br>&nbsp; response</span><span class="pun">.</span><span class="pln">end</span><span
class="pun">();</span><span class="pln"><br></span><span class="pun">}).</span><span
class="pln">listen</span><span class="pun">(</span><span class="lit">8888</span><span
class="pun">);</span></pre>
<p>
Pronto! Você escreveu um servidor HTTP. Vamos te provar executando
e testando. Primeiro, execute seu script com Node.js:
</p>
<pre>node server.js</pre>
<p>
Agora, abra seu navegador e coloque o endereço da url:
<a href="http://localhost:8888/" rel="nofollow">http://localhost:8888/</a>.
Com isso deve exibir uma página web com os dizeres "Olá Mundo".
</p>
<p>
Isso é muito interessante não é. Que tal falarmos sobre o que está
acontecendo aqui e deixar a questão de como organizar nosso projeto
para mais tarde? Eu prometo que voltaremos aqui.
</p>
<a name="analyzing-our-http-server"></a>
<h3>Analisando nosso servidor HTTP</h3>
<p>
Bom, então, vamos analisar o que realmente está acontecendo aqui.
</p>
<p>
A primeira linha <em>requer</em> o módulo <em>http</em> que já vem carregado
junto com o Node.js e se torna acessivel através da variável <em>http</em>.
</p>
<p>
Nós podemos então, chamar uma das funções que o módulo http oferece:
<em>createServer</em>. Essa função retorna um objeto, e este objeto
tem um método chamado <em>listen</em>, e passa como parâmetro um valor
numérico, o qual, indica o número da porta que nosso servidor HTT está
escutando.
</p>
<p>
Por favor, ignore a segunda função definida que possui parênteses
em aberto em: <em>http.createServer</em>.
</p>
<p>
Poderiamos ter escrito o código que inicia nosso servidor fazendo ele
escutar a porta 8888, como abaixo:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="kwd">var</span><span
class="pln"> server </span><span class="pun">=</span><span class="pln"> http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">();</span><span
class="pln"><br>server</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span></pre>
<p>
Este deverá iniciar um servidor HTTP, escutando a porta 8888 e nao fazer mais nada (nem mesmo responder a qualquer solicitação).
</p>
<p> A parte realmente interessante (e, se sua aplicação background for uma linguagem conservadora como php, olhando estranho) é a definição bem ali onde você espera o primeiro paramento na chamada do <em>createServer()</em>.
</p>
<p>
Acontece que, esta definição da função É o primeiro ( e único ) parametro que iremos passar na chamada do <em>createServer()</em>. Por que em JavaScript, funções podem ser passadas como qualquer outro valor.
</p>
<a name="passing-functions-around"></a>
<h3>Passando funções como um todo</h3>
<p>
Você pode, pode exemplo, fazer algo assim:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> say</span><span
class="pun">(</span><span class="pln">word</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span
class="pln">word</span><span class="pun">);</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> execute</span><span
class="pun">(</span><span class="pln">someFunction</span><span class="pun">,</span><span class="pln"> value</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; someFunction</span><span
class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>execute</span><span
class="pun">(</span><span class="pln">say</span><span class="pun">,</span><span
class="pln"> </span><span class="str">"Hello"</span><span class="pun">);</span></pre>
<p>
Leia cuidadosamente. O que estamos fazendo é, passando a
função <em>say</em> como primeiro parâmetro da função
<em>execute</em>. Não o valor retornado por
<em>say</em>, mas sim, a própria função <em>say</em>!
</p>
<p>
Assim, <em>say</em> torna-se a variável local
<em>someFunction</em> dentro da função <em>execute</em>, e
<em>execute</em> pode chamar a função nessa variável usando
<em>someFunction()</em> (adicionando parênteses).
</p>
<p>
Claro, por <em>say</em> receber um parâmetro,
<em>execute</em> pode passar tal parâmetro quando chamar
<em>someFunction</em>.
</p>
<p>
Podemos, como acabamos de fazer, passar uma função como parâmetro
para uma outra função através do seu nome. Mas não temos que seguir
essa direção de primeiro definir a função, depois passá-la - podemos
definir e passar uma função como parâmetro para outra função
no mesmo lugar:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> execute</span><span
class="pun">(</span><span class="pln">someFunction</span><span class="pun">,</span><span class="pln"> value</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; someFunction</span><span
class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>execute</span><span
class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span
class="pln">word</span><span class="pun">){</span><span class="pln"> console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span
class="pln">word</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">},</span><span class="pln"> </span><span class="str">"Hello"</span><span
class="pun">);</span></pre>
<p>
Definimos a função a ser passada para <em>execute</em>
ali mesmo, no lugar onde <em>execute</em> espera seu primeiro
parâmetro.
</p>
<p>
Dessa maneira, não precisamos fornecer um nome para a função,
sendo assim, chamando-a como uma função anônima (<em>anonymous function</em>).
</p>
<p>
Essa é a primeira mostra do que gosto de chamar Javascript “Avançado”,
mas vamos passo a passo. Por agora, vamos apenas aceitar que, em javascript,
podemos passar uma função como parâmetro quando chamada uma outra função.
Podemos fazer isso inserindo nossa função em uma variável que será passada
como parâmetro, ou definindo a função no próprio o local onde o parâmetro
é declarado.
</p>
<a name="how-function-passing-makes-our-http-server-work"></a>
<h3>Como a passagem de função faz nosso servidor HTTP trabalhar</h3>
<p>
Com este conhecimento, vamos voltar para o nosso minimalista
servidor HTTP:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br>http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">(</span><span class="kwd">function</span><span
class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; response</span><span
class="pun">.</span><span class="pln">writeHead</span><span class="pun">(</span><span
class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span
class="pun">{</span><span class="str">"Content-Type"</span><span class="pun">:</span><span
class="pln"> </span><span class="str">"text/plain"</span><span class="pun">});</span><span
class="pln"><br>&nbsp; response</span><span class="pun">.</span><span class="pln">write</span><span
class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span><span
class="pln"><br>&nbsp; response</span><span class="pun">.</span><span class="pln">end</span><span
class="pun">();</span><span class="pln"><br></span><span class="pun">}).</span><span
class="pln">listen</span><span class="pun">(</span><span class="lit">8888</span><span
class="pun">);</span></pre>
<p>
Agora deve estar claro o que realmente estamos fazendo aqui:
Passamos a função <em>createServer</em> de uma função anônima.
</p>
<p>
Poderiamos conseguir o mesmo efeito refatorando nosso código para:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> onRequest</span><span class="pun">(</span><span class="pln">request</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; response</span><span
class="pun">.</span><span class="pln">writeHead</span><span class="pun">(</span><span
class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span
class="pun">{</span><span class="str">"Content-Type"</span><span class="pun">:</span><span
class="pln"> </span><span class="str">"text/plain"</span><span class="pun">});</span><span
class="pln"><br>&nbsp; response</span><span class="pun">.</span><span class="pln">write</span><span
class="pun">(</span><span class="str">"Hello World"</span><span class="pun">);</span><span
class="pln"><br>&nbsp; response</span><span class="pun">.</span><span class="pln">end</span><span
class="pun">();</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>http</span><span
class="pun">.</span><span class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span></pre>
<p>
Talvez agora seja um bom momento para perguntar: Por que estamos fazendo desta
            maneira?
</p>
<a name="event-driven-callbacks"></a>
<h3>Direcionar callbacks de eventos assíncronos</h3>
<p>
Para entender por que os aplicativos Node.js tem que ser escrito dessa maneira,
precisamos entender como Node.js executa nosso código. Esta
abordagem não é única, mas o modelo de execução subjacente é
diferente de ambientes de execução, como Python, Ruby, PHP ou Java.
</p>
<p>
Vamos pegar um simples pedaço de código como este:
</p>
<pre class="prettyprint lang-js">var result = database.query("SELECT * FROM hugetable");
console.log("Hello World");</pre>
<p>
Por favor, ignore por enquanto que não tenhamos falado sobre
consulta com o banco de dados antes - é apenas um exemplo. A
primeira linha consulta um banco de dados com muitos registros, a segunda
linha coloca escrito "Olá Mundo" no console.
</p>
<p>
Vamos supor que a consulta no banco de dados é muito lenta, que para
ler uma grande quantidade de registros, levaria vários segundos.
</p>
<p>
A maneira que escrevemos este código, o interpretador JavaScript do
Node.js primeiro tem que ler o resultado completo do
banco de dados, e então ele executa a função <em>console.log()</em>.
</p>
<p>
Se este trecho de código fosse, digamos, PHP, ele iria trabalhar na
mesma maneira: ler todos os resultados de uma só vez, em seguida, executar a próxima linha
            de código. Se este código fosse parte de um script de uma página web, o usuário
            teria que esperar alguns segundos para a página carregar.
</p>
<p>
No entanto, no modelo de execução do PHP, isso não seria um
            problema "global": o servidor web inicia o seu processo para que o PHP
            receba todas as solicitações HTTP. Se uma dessas solicitações resultarem
            na execução de um trecho de código lento, este resultado efeta o
            carregamento da página para um usuário específico, mas outros usuários que solicitem
            outras páginas não seriam afetados.
</p>
<p>
O modelo de execução do Node.js é diferente - existe apenas um
            único processo. Se houver uma consulta do banco de dados lenta em algum lugar
            deste processo, isso afeta todo o processo - tudo fica
            parado até que a consulta lenta tenha terminado
</p>
<p>
Para evitar isso, o JavaScript, e portanto o Node.js, introduz o
            conceito de evento direcionado e callbacks assíncronos, utilizando de um
            ciclo de eventos.
</p>
<p>
Nós podemos entender este conceito analizado um versão reescrito
do nosso código problemático:
</p>
<pre class="prettyprint lang-js">database.query("SELECT * FROM hugetable", function(rows) {
var result = rows;
});
console.log("Hello World");</pre>
<p>
Aqui, em vez de esperar <em>database.query()</em> nós retornamos
            diretamente um resultado, passando como segundo parâmetro, uma função
anônima.
</p>
<p>
Na sua forma anterior, nosso código foi síncrono: <em>primeiro</em>
            fazemos a consulta de banco de dados, e só quando isso estiver feito, <em>então</em>
            escrevemos no console.
</p>
<p>
Agora, o Node.js pode lidar com o pedido do banco de dados de forma assíncrona.
            Desde que <em>database.query()</em> faça parte de uma biblioteca
            assíncrona, isto é o que Node.js faz: assim como antes, pega a
            consulta e envia para o banco de dados. Mas, em vez de esperar por ela
            ser concluída, ele faz uma nota mental que diz: "Quando em algum
            momento no futuro o servidor de banco de dados estiver concluído a operação
e enviar o resultado da consulta, então eu tenho que executar a função anônima
            que foi passado para <em>database.query()</em>."
</p>
<p>
Então, ele imediatamente executa <em>console.log()</ em> e
            depois, ele entra no ciclo de eventos. Node.js executa continuamente
            através desse ciclo de novo e de novo sempre que não há mais nada
            fazer, à espera de eventos. Eventos como, por exemplo, uma base de dados lenta
            consulta de finalmente entregar seus resultados.
</p>
<p>
Isso também explica por que o nosso servidor HTTP precisa de uma função que pode
            convocar os pedidos recebidos - se Node.js ser iniciado com o servidor
            e depois só fazer uma pausa, esperando o próximo pedido, continuando
            somente quando ele chegar, seria altamente ineficiente. Se um segundo
            usuário solicitar o servidor enquanto ele ainda está servindo o primeiro
            pedido, o segundo pedido só poderia ser atendido após o primeiro
            ser feito - assim se você tem um número grande de pedidos HTTP
            por segundo, isso não iria funcionar para todos.
</p>
<p>
É importante notar que esta assíncrono, single-threaded e
            está dirigindo eventos, de modo que o modelo de execução não é infinitamente escalável
            e com performance unicórnio com balas de prata em anexo. É apenas um
            de vários modelos, e tem suas limitações, sendo um deles que
            o Node.js é apenas um único processo, e que pode ser executado em apenas
            um núcleo único. Pessoalmente, acho que este modelo bastante
            acessível, porque permite escrever aplicações que têm de
            lidar com a concorrência de uma forma eficiente e relativamente
            direta.
</p>
<p>
Você pode querer ler o excelente post de
Felix Geisendörfer
<a href="http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb">Understanding
node.js</a>
para uma explicação adicional.
</p>
<p>
Vamos brincar um pouco com esse novo conceito. Podemos provar
            que o nosso código continua depois de criar o servidor, mesmo se
            nenhuma solicitação HTTP aconteceu e a função de retorno que foi
            passado não é chamado? Vamos tentar:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> onRequest</span><span class="pun">(</span><span class="pln">request</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request received."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello World"</span><span
class="pun">);</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br>http</span><span class="pun">.</span><span class="pln">createServer</span><span
class="pun">(</span><span class="pln">onRequest</span><span class="pun">).</span><span class="pln">listen</span><span
class="pun">(</span><span class="lit">8888</span><span class="pun">);</span><span class="pln"><br><br>console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span></pre>
<p>
Note que eu uso <em>console.log</em> para a saída de um texto sempre que
            a função <em>onRequest</em> (nosso callback) é acionado,
            e outro texto logo <em>após</em> iniciar o servidor HTTP.
</p>
<p>
Quando iniciamos este (<em> node server.js </ em>, como sempre), ele
            imediatamente gera a saída "Server foi iniciado." na
            linha de comando. Sempre que solicitar o nosso servidor (abrindo
<a href="http://localhost:8888/" rel="nofollow">http://localhost:8888/</a>
em nosso navegador), a mensagem "Pedido recebido." é impressa
            na linha de comando.
</p>
<p>
Direcionar eventos assíncrono JavaScript do lado do servidor com
            callbacks em ação :-)
</p>
<p>
Note que o nosso servidor irá provavelmente escrever "Pedido recebido."
            para STDOUT duas vezes ao abrir a página em um navegador. Isso é
            porque a maioria dos navegadores irá tentar carregar o favicon, solicitando
http://localhost:8888/favicon.ico sempre que abrir
http://localhost:8888/).
</p>
<a name="how-our-server-handles-requests"></a>
<h3>Como nosso servidor processa as requisições</h3>
<p>
Ok, vamos analisar rapidamente o resto do nosso código, servidor, que é
o corpo da nossa função callback <em>onRequest()</em>.
</p>
<p>
Quando o callback é disparado e nossa função <em>onRequest()</em> é acionada,
dois parâmetros são passados para ele: <em>request</em> e <em>response</em>.
</p>
<p>
Estes são objetos, e voce pode usar seus métodos para lidar com os detalhes da requisição HTTP que occoreram e para responder a requisição (ou seja, para realmente enviar alguma coisa sobre a parte traseira do fio para o navegador que solicitou o seu servidor ).
</p>
<p>
E nosso código faz justamente isto: Sempre que a requisição é recebida, é usado a função <em>response.writeHead()</em> para enviar um HTTP status 200 e o tipo de conteudo no cabeçalho da resposta HTTP, e a função <em>response.write()</em> envia o texto "Olá Mundo" no corpo da resposta HTTP.
</p>
<p>
E por último, chamamos <em>response.end()</em> para realmente terminar nossa resposta.
</p>
<p>
Neste ponto, não nos importamos com os detalhes da requisição, razão pela qual não usamos o objeto <em>request</em> em tudo.
</p>
<a name="finding-a-place-for-our-server-module"></a>
<h3>Finding a place for our server module</h3>
<p>
Ok, I promised we will get back to how to organize our
application. We have the code for a very basic HTTP server in
the file <em>server.js</em>, and I mentioned that it's common
to have a main file called <em>index.js</em> which is used
to bootstrap and start our application by making use of the
other modules of the application (like the HTTP server module
that lives in <em>server.js</em>).
</p>
<p>
Let's talk about how to make server.js a real Node.js module
that can be used by our yet-to-be-written <em>index.js</em>
main file.
</p>
<p>
As you may have noticed, we already used modules in our code,
like this:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="pun">...</span><span
class="pln"><br><br>http</span><span class="pun">.</span><span class="pln">createServer</span><span
class="pun">(...);</span></pre>
<p>
Somewhere within Node.js lives a module called "http", and we can
make use of it in our own code by requiring it and assigning
the result of the require to a local variable.
</p>
<p>
This makes our local variable an object that carries all the
public methods the <em>http</em> module provides.
</p>
<p>
It's common practice to choose the name of the module for the
name of the local variable, but we are free to choose whatever
we like:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> foo </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="pun">...</span><span
class="pln"><br><br>foo</span><span class="pun">.</span><span class="pln">createServer</span><span
class="pun">(...);</span></pre>
<p>
Fine, it's clear how to make use of internal Node.js modules. How
do we create our own modules, and how do we use them?
</p>
<p>
Let's find out by turning our <em>server.js</em> script into a
real module.
</p>
<p>
Turns out, we don't have to change that much. Making some code
a module means we need to <em>export</em> those parts of its
functionality that we want to provide to scripts that require
our module.
</p>
<p>
For now, the functionality our HTTP server needs to export is
simple: scripts requiring our server module simply need to
start the server.
</p>
<p>
To make this possible, we will put our server code into a
function named <em>start</em>, and we will export this
function:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span
class="pln"><br>&nbsp; </span><span class="kwd">function</span><span class="pln"> onRequest</span><span
class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request received."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello World"</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br><br>&nbsp; http</span><span class="pun">.</span><span
class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span></pre>
<p>
This way, we can now create our main file <em>index.js</em>,
and start our HTTP there, although the code for the server is
still in our <em>server.js</em> file.
</p>
<p>
Create a file <em>index.js</em> with the following content:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> server </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"./server"</span><span
class="pun">);</span><span class="pln"><br><br>server</span><span class="pun">.</span><span class="pln">start</span><span
class="pun">();</span></pre>
<p>
As you can see, we can use our server module just like any
internal module: by requiring its file and assigning it to
a variable, its exported functions become available to us.
</p>
<p>
That's it. We can now start our app via our main script, and it
still does exactly the same:
</p>
<pre>node index.js</pre>
<p>
Great, we now can put the different parts of our application
into different files and wire them together by making them
modules.
</p>
<p>
We still have only the very first part of our application in
place: we can receive HTTP requests. But we need to do
something with them - depending on which URL the browser
requested from our server, we need to react differently.
</p>
<p>
For a very simple application, you could do this directly
within the callback function <em>onRequest()</em>. But as I said,
let's add a bit more abstraction in order to make our example
application a bit more interesting.
</p>
<p>
Making different HTTP requests point at different parts of our
code is called "routing" - well, then, let's create a module
called <em>router</em>.
</p>
<a name="whats-needed-to-route-requests"></a>
<h3>What's needed to "route" requests?</h3>
<p>
We need to be able to feed the requested URL and possible
additional GET and POST parameters into our router, and based
on these the router then needs to be able to decide which code
to execute (this "code to execute" is the third part of our
application: a collection of request handlers that do the
actual work when a request is received).
</p>
<p>
So, we need to look into the HTTP requests and extract the
requested URL as well as the GET/POST parameters from them.
It could be argued if that should be part of the router or
part of the server (or even a module of its own), but let's
just agree on making it part of our HTTP server for now.
</p>
<p>
All the information we need is available through the
<em>request</em> object which is passed as the first parameter
to our callback function <em>onRequest()</em>. But to interpret
this information, we need some additional Node.js modules, namely
<em>url</em> and <em>querystring</em>.
</p>
<a name="head20"></a>
<p>
The <em>url</em> module provides methods which allow us to
extract the different parts of a URL (like e.g. the requested
path and query string), and <em>querystring</em> can in turn be
used to parse the query string for request parameters:
</p>
<pre> url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&amp;hello=world
--- -----
| |
| |
querystring(string)["foo"] |
|
querystring(string)["hello"]
</pre>
<p>
We can, of course, also use <em>querystring</em> to parse the
body of a POST request for parameters, as we will see
later.
</p>
<p>
Let's now add to our <em>onRequest()</em> function the logic
needed to find out which URL path the browser requested:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br></span><span
class="kwd">var</span><span class="pln"> url </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"url"</span><span
class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span
class="pln"><br>&nbsp; </span><span class="kwd">function</span><span class="pln"> onRequest</span><span
class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">var</span><span class="pln"> pathname </span><span class="pun">=</span><span class="pln"> url</span><span
class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span
class="pln">request</span><span class="pun">.</span><span class="pln">url</span><span
class="pun">).</span><span class="pln">pathname</span><span class="pun">;</span><span class="pln"><br>&nbsp; &nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname </span><span
class="pun">+</span><span class="pln"> </span><span class="str">" received."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello World"</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br><br>&nbsp; http</span><span class="pun">.</span><span
class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span></pre>
<p>
Fine. Our application can now distinguish requests based on the
URL path requested - this allows us to map requests to our
request handlers based on the URL path using our (yet to be
written) router.
</p>
<p>
In the context of our application, it simply means that we will
be able to have requests for the <em>/start</em> and
<em>/upload</em> URLs handled by different parts of our
code. We will see how everything fits together soon.
</p>
<p>
Ok, it's time to actually write our router. Create a new file
called <em>router.js</em>, with the following content:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> route</span><span
class="pun">(</span><span class="pln">pathname</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"About to route a request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">route </span><span class="pun">=</span><span
class="pln"> route</span><span class="pun">;</span></pre>
<p>
Of course, this code basically does nothing, but that's ok for
now. Let's first see how to wire together this router with our
server before putting more logic into the router.
</p>
<p>
Our HTTP server needs to know about and make use of our router.
We could hard-wire this dependency into the server, but because
we learned the hard way from our experience with other
programming languages, we are going to loosely couple server
and router by injecting this dependency (you may want to read
<a href="http://martinfowler.com/articles/injection.html">Martin Fowlers excellent post on Dependency Injection</a>
for background information).
</p>
<p>
Let's first extend our server's <em>start()</em> function in
order to enable us to pass the route function to be used by
parameter:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br></span><span
class="kwd">var</span><span class="pln"> url </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"url"</span><span
class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> start</span><span class="pun">(</span><span class="pln">route</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span
class="pln"><br>&nbsp; </span><span class="kwd">function</span><span class="pln"> onRequest</span><span
class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">var</span><span class="pln"> pathname </span><span class="pun">=</span><span class="pln"> url</span><span
class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span
class="pln">request</span><span class="pun">.</span><span class="pln">url</span><span
class="pun">).</span><span class="pln">pathname</span><span class="pun">;</span><span class="pln"><br>&nbsp; &nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname </span><span
class="pun">+</span><span class="pln"> </span><span class="str">" received."</span><span
class="pun">);</span><span class="pln"><br><br>&nbsp; &nbsp; route</span><span class="pun">(</span><span
class="pln">pathname</span><span class="pun">);</span><span
class="pln"><br><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello World"</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br><br>&nbsp; http</span><span class="pun">.</span><span
class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span></pre>
<p>
And let's extend our <em>index.js</em> accordingly, that is,
injecting the route function of our router into the server:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> server </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"./server"</span><span
class="pun">);</span><span class="pln"><br></span><span class="kwd">var</span><span
class="pln"> router </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"./router"</span><span class="pun">);</span><span class="pln"><br><br>server</span><span
class="pun">.</span><span class="pln">start</span><span class="pun">(</span><span
class="pln">router</span><span class="pun">.</span><span class="pln">route</span><span
class="pun">);</span><span class="pln"><br></span></pre>
<p>
Again, we are passing a function, which by now isn't any news
for us.
</p>
<p>
If we start our application now (<em>node index.js,
as always</em>), and request an URL, you can now see from the
application's output that our HTTP server makes use of our
router and passes it the requested pathname:
</p>
<pre>bash$ node index.js
Request for /foo received.
About to route a request for /foo</pre>
<p>
(I omitted the rather annoying output for the /favicon.ico
request).
</p>
<a name="execution-in-the-kongdom-of-verbs"></a>
<h3>Execution in the kingdom of verbs</h3>
<p>
May I once again stray away for a while and talk about
functional programming again?
</p>
<p>
Passing functions is not only a technical consideration.
With regard to software design, it's almost philosophical.
Just think about it: in our index file, we could have passed
the <em>router</em> object into the server, and the server
could have called this object's <em>route</em> function.
</p>
<p>
This way, we would have passed a <em>thing</em>, and the server
would have used this thing to <em>do</em> something. Hey,
router thing, could you please route this for me?
</p>
<p>
But the server doesn't need the thing. It only needs to get
something <em>done</em>, and to get something done, you don't
need things at all, you need <em>actions</em>. You don't need
<em>nouns</em>, you need <em>verbs</em>.
</p>
<p>
Understanding the fundamental mind-shift that's at the core of
this idea is what made me really understand functional
programming.
</p>
<p>
And I did understand it when reading Steve Yegge's masterpiece
<a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html">Execution in the Kingdom of Nouns</a>.
Go read it now, really. It's one of the best writings related
to software I ever had the pleasure to encounter.
</p>
<a name="routing-to-real-request-handlers"></a>
<h3>Routing to real request handlers</h3>
<p>
Back to business. Our HTTP server and our request router are
now best friends and talk to each other as we intended.
</p>
<p>
Of course, that's not enough. "Routing" means, we want to
handle requests to different URLs differently. We would like to
have the "business logic" for requests to <em>/start</em>
handled in another function than requests to <em>/upload</em>.
</p>
<p>
Right now, the routing "ends" in the router, and the router is
not the place to actually "do" something with the requests,
because that wouldn't scale well once our application becomes
more complex.
</p>
<a name="continuereading"></a>
<p>
Let's call these functions, where requests are routed to,
<em>request handlers</em>. And let's tackle those next, because
unless we have these in place there isn't much sense in doing
anything with the router for now.
</p>
</div>
<div id="salespitch">
<div id="bubble">
<img id="authorimage" src="manuelkiessling.jpg" width="160" height="160"/>
<p>
<br/>
Hi there! Sorry to interrupt you.
</p>
<p>
My name is Manuel Kiessling, I'm the author of this book.
</p>
<p>
If you have read that far, I guess I may assume that you like
the book. I'm pretty sure you also like the fact that it's free,
which is totally fine, and you can continue reading it for free,
which also is totally fine.
</p>
<p>
However, I would like you to consider buying the eBook version
of the book. It's a beautifully crafted package including a PDF,
an ePub, and a MOBI file, which means you can read it on all
kinds of eReaders out there like the Amazon Kindle, the Nook, or
the Sony Reader.
</p>
<p>
But the best thing about it is that it comes bundled with another
great Node.js book: <em>"Hands-on Node.js"</em> by Pedro Teixeira. It's a
complete reference that explains all the Node.js modules in great
detail - it's perfect to dig deeper once you finished <em>The Node
Beginner Book</em>.
</p>
<p>
Both books together would cost a total of $21.98, but we are offering
it as a bundle for only <strong>$9.99</strong>.
You can download it immediately, it's
completely DRM-free, and you will receive any future updates for
both books for free.
</p>
<p>
So, here are the two choices you have right now:
</p>
<div class="box">
<a href="buy-bundle/salespitch.html"><img src="the_node_beginner_book_cover_small.png" height="86" width="57" /></a>
<a href="buy-bundle/salespitch.html"><img src="hands-on_node.js_cover.png" height="86" width="57" /></a>
<br/>
<div class="subinfo">
226 pages in total<br/>
DRM-free<br/>
Free updates<br/>
<strong>Only $9.99</strong>
</div>
<a class="buttonlink" href="buy-bundle/salespitch.html">
<div class="button">Buy this<br />bundle now</div>
</a>
</div>
<div class="orbox">
<strong>OR</strong>
</div>
<div class="box">
<script type="text/javascript">
var showHiddenHalf = function() {
document.getElementById('hiddenhalf').style.opacity = '1.0';
document.getElementById('salespitch').style.display = 'none';
return false;
};
</script>
<a href="#continuereading" onclick="showHiddenHalf();">Continue reading<br/>the free version</a>
</div>
</div>
<br clear="all"/>
</div>
<div id="hiddenhalf">
<p>
New application part, new module - no surprise here. Let's
create a module called requestHandlers, add a placeholder
function for every request handler, and export these as
methods of the module:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> start</span><span
class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'start' was called."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span
class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> upload</span><span
class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'upload' was called."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span><span class="pln"><br>exports</span><span
class="pun">.</span><span class="pln">upload </span><span class="pun">=</span><span
class="pln"> upload</span><span class="pun">;</span></pre>
<p>
This allows us to wire the request handlers into the router,
giving our router something to route to.
</p>
<p>
At this point we need to make a decision: do we hard-code usage
of the requestHandlers module into the router, or do we want a
bit more dependency injection? Although dependency injection,
like every other pattern, shouldn't be used only for the sake
of using it, in this case it makes sense to loosely couple the
router and its request handlers, and thus making the router
really reusable.
</p>
<p>
This means we need to pass the request handlers from our server
into our router, but this feels even more wrong, which is why
we should go the whole way and pass them to the server from our
main file, and passing it on to the router from there.
</p>
<p>
How are we going to pass them? Right now we have two handlers,
but in a real application, this number is going to increase and
vary, and we sure don't want to fiddle around mapping requests
to handlers in the router anytime a new URL / request handler
is added. And having some
<em>if request == x then call handler y</em> in the router
would be more than ugly.
</p>
<p>
A varying number of items, each mapped to a string (the
requested URL)? Well, sounds like an associative array would be
a perfect fit.
</p>
<p>
Well, this finding is slightly disappointed by the fact that
JavaScript doesn't provide associative array - or does it?
Turns out, it's actually objects that we want to use if we need
an associative array!
</p>
<p>
There's a nice introduction to this at
<a href="http://msdn.microsoft.com/en-us/magazine/cc163419.aspx">http://msdn.microsoft.com/en-us/magazine/cc163419.aspx</a>,
let me quote the relevant part:
</p>
<blockquote>
<p>
In C++ or C#, when we’re talking about objects, we're
referring to instances of classes or structs. Objects have
different properties and methods, depending on which
templates (that is, classes) they are instantiated from.
That's not the case with JavaScript objects. In JavaScript,
objects are just collections of name/value pairs - think of a
JavaScript object as a dictionary with string keys.
</p>
</blockquote>
<p>
If JavaScript objects are just collections of name/value pairs,
how can they have methods? Well, the values can be strings,
numbers etc. - or functions!
</p>
<p>
Ok, now finally back to the code. We decided we want to pass
the list of requestHandlers as an object, and in order to
achieve loose coupling we want to inject this object into the
<em>route()</em>.
</p>
<p>
Let's start with putting the object together in our main file
<em>index.js</em>:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> server </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"./server"</span><span
class="pun">);</span><span class="pln"><br></span><span class="kwd">var</span><span
class="pln"> router </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"./router"</span><span class="pun">);</span><span class="pln"><br></span><span class="kwd">var</span><span
class="pln"> requestHandlers </span><span class="pun">=</span><span class="pln"> require</span><span
class="pun">(</span><span class="str">"./requestHandlers"</span><span class="pun">);</span><span
class="pln"><br><br></span><span class="kwd">var</span><span class="pln"> handle </span><span
class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span
class="pln"><br>handle</span><span class="pun">[</span><span class="str">"/"</span><span
class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> requestHandlers</span><span
class="pun">.</span><span class="pln">start</span><span class="pun">;</span><span class="pln"><br>handle</span><span
class="pun">[</span><span class="str">"/start"</span><span class="pun">]</span><span
class="pln"> </span><span class="pun">=</span><span class="pln"> requestHandlers</span><span
class="pun">.</span><span class="pln">start</span><span class="pun">;</span><span class="pln"><br>handle</span><span
class="pun">[</span><span class="str">"/upload"</span><span class="pun">]</span><span
class="pln"> </span><span class="pun">=</span><span class="pln"> requestHandlers</span><span
class="pun">.</span><span class="pln">upload</span><span class="pun">;</span><span class="pln"><br><br>server</span><span
class="pun">.</span><span class="pln">start</span><span class="pun">(</span><span
class="pln">router</span><span class="pun">.</span><span class="pln">route</span><span
class="pun">,</span><span class="pln"> handle</span><span class="pun">);</span></pre>
<p>
Although <em>handle</em> is more of a "thing" (a collection of
request handlers), I propose we name it like a verb, because
this will result in a fluent expression in our router, as we
will see soon.
</p>
<p>
As you can see, it's really simple to map different URLs to the
same request handler: by adding a key/value pair of
<em>"/"</em> and <em>requestHandlers.start</em>, we can express
in a nice and clean way that not only requests to
<em>/start</em>, but also requests to <em>/</em> shall be
handled by the <em>start</em> handler.
</p>
<p>
After defining our object, we pass it into the server as an
additional parameter. Let's change our <em>server.js</em> to
make use of it:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br></span><span
class="kwd">var</span><span class="pln"> url </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"url"</span><span
class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> start</span><span class="pun">(</span><span class="pln">route</span><span
class="pun">,</span><span class="pln"> handle</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; </span><span class="kwd">function</span><span
class="pln"> onRequest</span><span class="pun">(</span><span class="pln">request</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">var</span><span class="pln"> pathname </span><span class="pun">=</span><span class="pln"> url</span><span
class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span
class="pln">request</span><span class="pun">.</span><span class="pln">url</span><span
class="pun">).</span><span class="pln">pathname</span><span class="pun">;</span><span class="pln"><br>&nbsp; &nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname </span><span
class="pun">+</span><span class="pln"> </span><span class="str">" received."</span><span
class="pun">);</span><span class="pln"><br><br>&nbsp; &nbsp; route</span><span class="pun">(</span><span
class="pln">handle</span><span class="pun">,</span><span class="pln"> pathname</span><span class="pun">);</span><span
class="pln"><br><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello World"</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br><br>&nbsp; http</span><span class="pun">.</span><span
class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span></pre>
<p>
We've added the <em>handle</em> parameter to our
<em>start()</em> function, and pass the handle object on to
the <em>route()</em> callback, as its first parameter.
</p>
<p>
Let's change the <em>route()</em> function accordingly, in our
<em>router.js</em> file:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> route</span><span
class="pun">(</span><span class="pln">handle</span><span class="pun">,</span><span
class="pln"> pathname</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span class="str">"About to route a request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="kwd">if</span><span
class="pln"> </span><span class="pun">(</span><span class="kwd">typeof</span><span
class="pln"> handle</span><span class="pun">[</span><span class="pln">pathname</span><span
class="pun">]</span><span class="pln"> </span><span class="pun">===</span><span
class="pln"> </span><span class="str">'function'</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; handle</span><span
class="pun">[</span><span class="pln">pathname</span><span class="pun">]();</span><span class="pln"><br>&nbsp; </span><span
class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"No request handler found for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">route </span><span class="pun">=</span><span
class="pln"> route</span><span class="pun">;</span></pre>
<p>
What we do here is, we check if a request handler for the given
pathname exists, and if it does, we simply call the corresponding
function. Because we can access our request handler functions
from our object just as we would access an element of an
associative array, we have this nice fluent
<em>handle[pathname]();</em> expression I talked about earlier:
"Please, <em>handle</em> this <em>pathname</em>".
</p>
<p>
Ok, that's all we need to wire server, router, and request
handlers together! When starting our application and requesting
<a href="http://localhost:8888/start" rel="nofollow">http://localhost:8888/start</a>
in our browser, we can prove that the correct request handler
was indeed called:
</p>
<pre>Server has started.
Request for /start received.
About to route a request for /start
Request handler 'start' was called.</pre>
<p>
And opening <a href="http://localhost:8888/" rel="nofollow">http://localhost:8888/</a>
in our browser proves that these requests, too, are indeed handled by
the <em>start</em> request handler:
</p>
<pre>Request for / received.
About to route a request for /
Request handler 'start' was called.</pre>
<a name="making-the-request-handlers-respond"></a>
<h3>Making the request handlers respond</h3>
<p>
Beautiful. Now if only the request handlers could actually send
something back to the browser, that would be even better,
right?
</p>
<p>
Remember, the "Hello World" your browser displays upon
requesting a page still comes from the <em>onRequest</em>
function in our <em>server.js</em> file.
</p>
<p>
"Handling request" means "answering requests" after all, thus
we need to enable our request handlers to speak with the
browser just like our <em>onRequest</em> function does.
</p>
<a name="how-to-not-do-it"></a>
<h4>How to not do it</h4>
<p>
The straight-forward approach we - as developers with a
background in PHP or Ruby - might want to follow is actually
very deceitful: it works like a charm, seems to make a lot of
sense, and then suddenly screws things up when we don't expect
it.
</p>
<p>
What I mean by "straight-forward approach" is this: make the
request handlers <em>return()</em> the content they want to
display to the user, and send this response data in the
<em>onRequest</em> function back to the user.
</p>
<p>
Let's just do this, and then see why it's not such an overly
good idea.
</p>
<p>
We start with the request handlers and make them return what we
would like to display in the browser. We need to change
<em>requestHandlers.js</em> to this:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> start</span><span
class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'start' was called."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="kwd">return</span><span
class="pln"> </span><span class="str">"Hello Start"</span><span class="pun">;</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> upload</span><span class="pun">()</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span
class="str">"Request handler 'upload' was called."</span><span class="pun">);</span><span
class="pln"><br>&nbsp; </span><span class="kwd">return</span><span class="pln"> </span><span
class="str">"Hello Upload"</span><span class="pun">;</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br>exports</span><span class="pun">.</span><span class="pln">start </span><span
class="pun">=</span><span class="pln"> start</span><span class="pun">;</span><span class="pln"><br>exports</span><span
class="pun">.</span><span class="pln">upload </span><span class="pun">=</span><span
class="pln"> upload</span><span class="pun">;</span></pre>
<p>
Good. Likewise, the router needs to return to the server what
the request handlers return to him. We therefore need to edit
<em>router.js</em> like this:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> route</span><span
class="pun">(</span><span class="pln">handle</span><span class="pun">,</span><span
class="pln"> pathname</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span class="str">"About to route a request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="kwd">if</span><span
class="pln"> </span><span class="pun">(</span><span class="kwd">typeof</span><span
class="pln"> handle</span><span class="pun">[</span><span class="pln">pathname</span><span
class="pun">]</span><span class="pln"> </span><span class="pun">===</span><span
class="pln"> </span><span class="str">'function'</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">return</span><span class="pln"> handle</span><span class="pun">[</span><span class="pln">pathname</span><span
class="pun">]();</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span class="str">"No request handler found for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="kwd">return</span><span
class="pln"> </span><span class="str">"404 Not found"</span><span class="pun">;</span><span class="pln"><br>&nbsp; </span><span
class="pun">}</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">route </span><span class="pun">=</span><span
class="pln"> route</span><span class="pun">;</span></pre>
<p>
As you can see, we also return some text if the request could
not be routed.
</p>
<p>
And last but not least, we need to refactor our server to make
it respond to the browser with the content the request handlers
returned via the router, transforming <em>server.js</em> into:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br></span><span
class="kwd">var</span><span class="pln"> url </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"url"</span><span
class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> start</span><span class="pun">(</span><span class="pln">route</span><span
class="pun">,</span><span class="pln"> handle</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; </span><span class="kwd">function</span><span
class="pln"> onRequest</span><span class="pun">(</span><span class="pln">request</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">var</span><span class="pln"> pathname </span><span class="pun">=</span><span class="pln"> url</span><span
class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span
class="pln">request</span><span class="pun">.</span><span class="pln">url</span><span
class="pun">).</span><span class="pln">pathname</span><span class="pun">;</span><span class="pln"><br>&nbsp; &nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname </span><span
class="pun">+</span><span class="pln"> </span><span class="str">" received."</span><span
class="pun">);</span><span class="pln"><br><br>&nbsp; &nbsp; response</span><span
class="pun">.</span><span class="pln">writeHead</span><span class="pun">(</span><span
class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span
class="pun">{</span><span class="str">"Content-Type"</span><span class="pun">:</span><span
class="pln"> </span><span class="str">"text/plain"</span><span class="pun">});</span><span
class="pln"><br>&nbsp; &nbsp; </span><span class="kwd">var</span><span class="pln"> content </span><span
class="pun">=</span><span class="pln"> route</span><span class="pun">(</span><span
class="pln">handle</span><span class="pun">,</span><span class="pln"> pathname</span><span
class="pun">)</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="pln">content</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br><br>&nbsp; http</span><span class="pun">.</span><span
class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span></pre>
<p>
If we start our rewritten application, everything works like
a charm: requesting <a href="http://localhost:8888/start" rel="nofollow">http://localhost:8888/start</a>
results in "Hello Start" being displayed in the browser,
requesting <a href="http://localhost:8888/upload" rel="nofollow">http://localhost:8888/upload</a>
gives us "Hello Upload", and <a href="http://localhost:8888/foo" rel="nofollow">http://localhost:8888/foo</a>
produces "404 Not found".
</p>
<p>
Ok, then why is that a problem? The short answer: because we
will run into problems if one of the request handlers wants to make
use of a non-blocking operation in the future.
</p>
<p>
Let's take a bit more time for the long answer.
</p>
<a name="blocking-and-non-blocking"></a>
<h4>Blocking and non-blocking</h4>
<p>
As said, the problems will arise when we include non-blocking
operations in the request handlers. But let's talk about
blocking operations first, then about non-blocking operations.
</p>
<p>
And instead of trying to explain what "blocking" and
"non-blocking" means, let's demonstrate ourselves what happens
if we add a blocking operation to our request handlers.
</p>
<p>
To do this, we will modify our <em>start</em> request handler
to make it wait 10 seconds before returning its "Hello Start"
string. Because there is no such thing as <em>sleep()</em> in
JavaScript, we will use a clever hack for that.
</p>
<p>
Please modify <em>requestHandlers.js</em> as follows:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> start</span><span
class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'start' was called."</span><span
class="pun">);</span><span class="pln"><br><br>&nbsp; </span><span class="kwd">function</span><span
class="pln"> sleep</span><span class="pun">(</span><span class="pln">milliSeconds</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">var</span><span class="pln"> startTime </span><span class="pun">=</span><span
class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span
class="typ">Date</span><span class="pun">().</span><span class="pln">getTime</span><span
class="pun">();</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="kwd">while</span><span
class="pln"> </span><span class="pun">(</span><span class="kwd">new</span><span
class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span
class="pln">getTime</span><span class="pun">()</span><span class="pln"> </span><span
class="pun">&lt;</span><span class="pln"> startTime </span><span class="pun">+</span><span class="pln"> milliSeconds</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br><br>&nbsp; sleep</span><span class="pun">(</span><span class="lit">10000</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="kwd">return</span><span
class="pln"> </span><span class="str">"Hello Start"</span><span class="pun">;</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> upload</span><span class="pun">()</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span
class="str">"Request handler 'upload' was called."</span><span class="pun">);</span><span
class="pln"><br>&nbsp; </span><span class="kwd">return</span><span class="pln"> </span><span
class="str">"Hello Upload"</span><span class="pun">;</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br>exports</span><span class="pun">.</span><span class="pln">start </span><span
class="pun">=</span><span class="pln"> start</span><span class="pun">;</span><span class="pln"><br>exports</span><span
class="pun">.</span><span class="pln">upload </span><span class="pun">=</span><span
class="pln"> upload</span><span class="pun">;</span></pre>
<p>
Just to make clear what that does: when the function
<em>start()</em> is called, Node.js waits 10 seconds and only then
returns "Hello Start". When calling <em>upload()</em>, it
returns immediately, just like before.
</p>
<p>
(Of course, you should imagine that instead of sleeping for
10 seconds, there would be a real life blocking operation in
<em>start()</em>, like some sort of long-running computation.)
</p>
<p>
Let's see what this change does.
</p>
<p>
As always, we need to restart our server. This time, I ask you
to follow a slightly complex "protocol" in order to see what
happens: First, open two browser windows or tabs. In the first
browser window, please enter <a href="http://localhost:8888/start" rel="nofollow">http://localhost:8888/start</a>
into the address bar, but do not yet open this url!
</p>
<p>
In the second browser window's address bar, enter <a href="http://localhost:8888/upload" rel="nofollow">http://localhost:8888/upload</a>,
and again, please do not yet hit enter.
</p>
<p>
Now, do as follows: hit enter on the first window ("/start"),
then quickly change to the second window ("/upload") and hit
enter, too.
</p>
<p>
What you will notice is this: The /start URL takes 10 seconds
to load, as we would expect. But the /upload URL <em>also</em>
takes 10 seconds to load, although there is no <em>sleep()</em>
in the corrsponding request handler.
</p>
<p>
Why? Because <em>start()</em> contains a blocking operation.
We already talked about Node's execution model - expensive
operations are ok, but we must take care to not block the Node.js
process with them. Instead, whenever expensive operations must be
executed, these must be put in the background, and their events
must be handled by the event loop.
</p>
<p>
And we will now see why the way we constructed the "request
handler response handling" in our application doesn't allow us
to make proper use of non-blocking operations.
</p>
<p>
Once again, let's try to experience the problem first-hand by
modifying our application.
</p>
<p>
We are going to use our <em>start</em> request handler for this
again. Please modify it to reflect the following (file
<em>requestHandlers.js</em>):
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> exec </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">"child_process"</span><span
class="pun">).</span><span class="pln">exec</span><span class="pun">;</span><span
class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> start</span><span
class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'start' was called."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="kwd">var</span><span class="pln"> content </span><span
class="pun">=</span><span class="pln"> </span><span class="str">"empty"</span><span class="pun">;</span><span
class="pln"><br><br>&nbsp; exec</span><span class="pun">(</span><span class="str">"ls -lah"</span><span
class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span
class="pln"> </span><span class="pun">(</span><span class="pln">error</span><span
class="pun">,</span><span class="pln"> stdout</span><span class="pun">,</span><span
class="pln"> stderr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span
class="pln"><br>&nbsp; &nbsp; content </span><span class="pun">=</span><span
class="pln"> stdout</span><span class="pun">;</span><span class="pln"><br>&nbsp; </span><span
class="pun">});</span><span class="pln"><br><br>&nbsp; </span><span class="kwd">return</span><span
class="pln"> content</span><span class="pun">;</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> upload</span><span
class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'upload' was called."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="kwd">return</span><span
class="pln"> </span><span class="str">"Hello Upload"</span><span class="pun">;</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span><span class="pln"><br>exports</span><span
class="pun">.</span><span class="pln">upload </span><span class="pun">=</span><span
class="pln"> upload</span><span class="pun">;</span></pre>
<p>
As you can see, we just introduced a new Node.js module,
<em>child_process</em>. We did so because it allows us to make
use of a very simple yet useful non-blocking operation:
<em>exec()</em>.
</p>
<p>
What <em>exec()</em> does is, it executes a shell command from
within Node.js. In this example, we are going to use it to get
a list of all files in the current directory ("ls -lah"),
allowing us to display this list in the browser of a user
requesting the <em>/start</em> URL.
</p>
<p>
What the code does is straightforward: create a new variable
<em>content</em> (with an initial value of "empty"), execute
"ls -lah", fill the variable with the result, and return it.
</p>
<p>
As always, we will start our application, and visit
<a href="http://localhost:8888/start" rel="nofollow">http://localhost:8888/start</a>.
</p>
<p>
Which loads a beautiful web page that displays the string
"empty". What's going wrong here?
</p>
<p>
Well, as you may have already guessed, <em>exec()</em> does its
magic in a non-blocking fashion. That's a good thing, because
this way we can execute very expensive shell operations (like,
e.g., copying huge files around or similar stuff) without
forcing our application into a full stop as the blocking
<em>sleep</em> operation did.
</p>
<p>
(If you would like to prove this, replace "ls -lah" with a
more expensive operation like "find /").
</p>
<p>
But we aren't exactly happy with our elegant non-blocking
operation, when our browser doesn't display its result, right?
</p>
<p>
Well, then, let's fix it. And while we are at it, let's try to
understand why the current architecture doesn't work.
</p>
<p>
The problem is that <em>exec()</em>, in order to work
non-blocking, makes use of a callback function.
</p>
<p>
In our example, it's an anonymous function which is passed as
the second parameter to the <em>exec()</em> function call:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> </span><span
class="pun">(</span><span class="pln">error</span><span class="pun">,</span><span
class="pln"> stdout</span><span class="pun">,</span><span class="pln"> stderr</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; content </span><span
class="pun">=</span><span class="pln"> stdout</span><span class="pun">;</span><span
class="pln"><br></span><span class="pun">}</span></pre>
<p>
And herein lies the root of our problem: our own code is
executed synchronous, which means that immediately after
calling <em>exec()</em>, Node.js continues to execute
<em>return content;</em>. At this point, <em>content</em> is
still "empty", due to the fact that the callback function
passed to <em>exec()</em> has not yet been called - because
<em>exec()</em> operates asynchronous.
</p>
<p>
Now, "ls -lah" is a very inexpensive and fast operation (unless
there are millions of files in the directory). Which is why the
callback is called relatively expeditious - but it nevertheless
happens asynchronously.
</p>
<p>
Thinking about a more expensive command makes this more
obvious: "find /" takes about 1 minute on my
machine, but if I replace "ls -lah" with "find /" in the
request handler, I still immediately receive an HTTP response
when opening the /start URL - it's clear that <em>exec()</em>
does something in the background, while Node.js itself
continues with the application, and we may assume that the
callback function we passed into <em>exec()</em> will be called
only when the "find /" command has finished running.
</p>
<p>
But how can we achieve our goal, i.e. showing the user a list
of files in the current directory?
</p>
<p>
Well, after learning how to <em>not</em> do it, let's discuss
how to make our request handlers respond to browser requests
the right way.
</p>
<a name="responding-request-handlers-with-non-blocking-operations"></a>
<h4>Responding request handlers with non-blocking operations</h4>
<p>
I've just used the phrase "the right way". Dangerous stuff.
Quite often, there is no single "right way".
</p>
<p>
But one possible solution for this is, as often with Node.js,
to pass functions around. Let's examine this.
</p>
<p>
Right now, our application is able to transport the content
(which the request handlers would like to display to the user)
from the request handlers to the HTTP server by returning it
up through the layers of the application (request handler -&gt;
router -&gt; server).
</p>
<p>
Our new approach is as follows: instead of bringing the content
to the server, we will bring the server to the content. To be
more precise, we will inject the <em>response</em> object (from
our server's callback function <em>onRequest()</em>) through
the router into the request handlers. The handlers will then be
able to use this object's functions to respond to requests
themselves.
</p>
<p>
Enough explanation, here is the step by step recipe on how to
change our application.
</p>
<p>
Let's start with our <em>server.js</em>:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> http </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span
class="str">"http"</span><span class="pun">);</span><span class="pln"><br></span><span
class="kwd">var</span><span class="pln"> url </span><span class="pun">=</span><span
class="pln"> require</span><span class="pun">(</span><span class="str">"url"</span><span
class="pun">);</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> start</span><span class="pun">(</span><span class="pln">route</span><span
class="pun">,</span><span class="pln"> handle</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; </span><span class="kwd">function</span><span
class="pln"> onRequest</span><span class="pun">(</span><span class="pln">request</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">var</span><span class="pln"> pathname </span><span class="pun">=</span><span class="pln"> url</span><span
class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span
class="pln">request</span><span class="pun">.</span><span class="pln">url</span><span
class="pun">).</span><span class="pln">pathname</span><span class="pun">;</span><span class="pln"><br>&nbsp; &nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname </span><span
class="pun">+</span><span class="pln"> </span><span class="str">" received."</span><span
class="pun">);</span><span class="pln"><br><br>&nbsp; &nbsp; route</span><span class="pun">(</span><span
class="pln">handle</span><span class="pun">,</span><span class="pln"> pathname</span><span
class="pun">,</span><span class="pln"> response</span><span class="pun">);</span><span class="pln"><br>&nbsp; </span><span
class="pun">}</span><span class="pln"><br><br>&nbsp; http</span><span class="pun">.</span><span
class="pln">createServer</span><span class="pun">(</span><span class="pln">onRequest</span><span
class="pun">).</span><span class="pln">listen</span><span class="pun">(</span><span
class="lit">8888</span><span class="pun">);</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Server has started."</span><span
class="pun">);</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span
class="pln"> start</span><span class="pun">;</span></pre>
<p>
Instead of expecting a return value from the <em>route()</em>
function, we pass it a third parameter, our <em>response</em>
object. Furthermore, we removed any <em>response</em> method
calls from the <em>onRequest()</em> handler, because we now
expect <em>route</em> to take care of that.
</p>
<p>
Next comes <em>router.js</em>:
</p>
<pre class="prettyprint lang-js"><span class="kwd">function</span><span class="pln"> route</span><span
class="pun">(</span><span class="pln">handle</span><span class="pun">,</span><span
class="pln"> pathname</span><span class="pun">,</span><span class="pln"> response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"About to route a request for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="kwd">if</span><span
class="pln"> </span><span class="pun">(</span><span class="kwd">typeof</span><span
class="pln"> handle</span><span class="pun">[</span><span class="pln">pathname</span><span
class="pun">]</span><span class="pln"> </span><span class="pun">===</span><span
class="pln"> </span><span class="str">'function'</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; handle</span><span
class="pun">[</span><span class="pln">pathname</span><span class="pun">](</span><span class="pln">response</span><span
class="pun">);</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; console</span><span class="pun">.</span><span
class="pln">log</span><span class="pun">(</span><span class="str">"No request handler found for "</span><span
class="pln"> </span><span class="pun">+</span><span class="pln"> pathname</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">404</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"404 Not found"</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; </span><span class="pun">}</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br>exports</span><span
class="pun">.</span><span class="pln">route </span><span class="pun">=</span><span
class="pln"> route</span><span class="pun">;</span></pre>
<p>
Same pattern: instead of expecting a return value from our
request handlers, we pass the <em>response</em> object on.
</p>
<p>
If no request handler can be used, we now take care of
responding with a proper "404" header and body ourselves.
</p>
<p>
And last but not least, we modify <em>requestHandlers.js</em>:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> exec </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">"child_process"</span><span
class="pun">).</span><span class="pln">exec</span><span class="pun">;</span><span
class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> start</span><span
class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'start' was called."</span><span
class="pun">);</span><span class="pln"><br><br>&nbsp; exec</span><span class="pun">(</span><span
class="str">"ls -lah"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span
class="pln"> </span><span class="pun">(</span><span class="pln">error</span><span
class="pun">,</span><span class="pln"> stdout</span><span class="pun">,</span><span
class="pln"> stderr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span
class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="pln">stdout</span><span
class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; </span><span class="pun">});</span><span
class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br></span><span class="kwd">function</span><span
class="pln"> upload</span><span class="pun">(</span><span class="pln">response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'upload' was called."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello Upload"</span><span
class="pun">);</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">end</span><span class="pun">();</span><span class="pln"><br></span><span
class="pun">}</span><span class="pln"><br><br>exports</span><span class="pun">.</span><span class="pln">start </span><span
class="pun">=</span><span class="pln"> start</span><span class="pun">;</span><span class="pln"><br>exports</span><span
class="pun">.</span><span class="pln">upload </span><span class="pun">=</span><span
class="pln"> upload</span><span class="pun">;</span></pre>
<p>
Our handler functions need to accept the response parameter,
and have to make use of them in order to respond to the
request directly.
</p>
<p>
The <em>start</em> handler will respond from within the
anonymous <em>exec()</em> callback, and the <em>upload</em>
handler still simply replies with "Hello Upload", but now
by making use of the <em>response</em> object.
</p>
<p>
If we start our application again (<em>node index.js</em>),
this should work as expected.
</p>
<p>
If you would like to prove that an expensive operation behind
<em>/start</em> will no longer block requests for
<em>/upload</em> from answering immediately, then modify your
<em>requestHandlers.js</em> as follows:
</p>
<pre class="prettyprint lang-js"><span class="kwd">var</span><span class="pln"> exec </span><span
class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">"child_process"</span><span
class="pun">).</span><span class="pln">exec</span><span class="pun">;</span><span
class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> start</span><span
class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span
class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'start' was called."</span><span
class="pun">);</span><span class="pln"><br><br>&nbsp; exec</span><span class="pun">(</span><span
class="str">"find /"</span><span class="pun">,</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="pun">{</span><span class="pln"> timeout</span><span class="pun">:</span><span
class="pln"> </span><span class="lit">10000</span><span class="pun">,</span><span
class="pln"> maxBuffer</span><span class="pun">:</span><span class="pln"> </span><span
class="lit">20000</span><span class="pun">*</span><span class="lit">1024</span><span
class="pln"> </span><span class="pun">},</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span
class="pln">error</span><span class="pun">,</span><span class="pln"> stdout</span><span
class="pun">,</span><span class="pln"> stderr</span><span class="pun">)</span><span class="pln"> </span><span
class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; response</span><span
class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span
class="pln">stdout</span><span class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; response</span><span
class="pun">.</span><span class="pln">end</span><span class="pun">();</span><span class="pln"><br>&nbsp; &nbsp; </span><span
class="pun">});</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br><br></span><span
class="kwd">function</span><span class="pln"> upload</span><span class="pun">(</span><span class="pln">response</span><span
class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; console</span><span
class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Request handler 'upload' was called."</span><span
class="pun">);</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">writeHead</span><span class="pun">(</span><span class="lit">200</span><span
class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span
class="str">"Content-Type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"text/plain"</span><span
class="pun">});</span><span class="pln"><br>&nbsp; response</span><span class="pun">.</span><span
class="pln">write</span><span class="pun">(</span><span class="str">"Hello Uplo