Módulo HTTP (Core Modules)
Seja muito bem vindo a uma das lições mais importantes da jornada NodeJS, a lição que vai te ensinar tudo o que você precisa saber sobre o módulo HTTP
, e como configurar seu primeiro servidor com ele.
O módulo HTTP
é de extrema importância, pois é a partir dele que conseguimos criar um SERVIDOR ONLINE, ou seja, uma aplicação que pode servir páginas HTML
, ou qualquer outro tipo de informação, seja um JSON
, XML ou qualquer outro formato.
O módulo HTTP
, está presente em 90% das aplicações feitas com NodeJS, pois como vimos em lições passadas, o NodeJS é um ambiente de desenvolvimento voltado para aplicações web. Logo, não tem como falar de uma aplicação web, sem falar no protocolo HTTP
🙂
Além disso, a maioria (se não todas) as bibliotecas e frameworks do NodeJS, que fornecem funcionalidades voltadas para a construção de servidores web e APIs (como Express, Hapi, Koa e etc...), utilizam o módulo HTTP
por de baixo dos panos para abstrair muitas das operações de baixo nível.
Por esse motivo, entender o funcionamento desse módulo é de vítal importância para a sua jornada como desenvolvedor NodeJS.
Agora chega de papo, e vamos entrar de cabeça nas funciondalides presentes neste módulo 🙃
O que é o Módulo HTTP?
Considerado um dos core modules do NodeJS, o módulo HTTP
fornece utilitários para criar servidores e clientes HTTP
, permitindo que você faça tudo, desde servir páginas web simples até construir APIs robustas.
Ele atua como o cerne principal da lógica do funcionamento das requisições da web. Pois será atrávés dele que você conseguirá ouvir, e responder suas solicitações HTTP
.
Por de baixo dos panos, essa biblioteca possui todos os recursos necessários para levantar um servidor local, de modo que você consiga acessar a URL http://localhost:PORTA no seu navegador, e com isso ter acesso ao seu próprio servidor.
E tudo isso pode ser feito usando poucas linhas de códigos, ou você prefere configurar tudo isso usando milhares de linhas, configurando IP, HTTP, TCP... manualmente?
A verdade, é que construir um servidor ou cliente HTTP
sem o módulo HTTP
do NodeJS, ou quem sabe, sem um módulo de rede especializado, seria uma tarefa bastante complexa e desafiadora.
Isso se deve ao fato de que o protocolo HTTP
é relativamente complexo, envolvendo uma série de detalhes técnicos, e regras que precisam ser implementadas corretamente para garantir a comunicação adequada entre o cliente (seu navegador) e o servidor (sua aplicação).
O intuito dessa lição, não é te ensinar a criar um servidor HTTP do ZERO, ok? Portanto vamos continuar cortando um longo caminho usando o módulo HTTP.
Qual a probabilidade de eu precisar criar um servidor HTTP do ZERO?
Com relação a isso, você pode ficar super tranquilo, pois a probabilidade é baíxíssima, ao menos que você esteja desenvolvimento uma aplicação HTTP
totalmente customizada, ou quem sabe, criando uma biblioteca similar ao Express
, Hapi
e entre outras.
E não... o módulo HTTP
não é limitado, com ele você consegue criar diversas aplicações web escáláveis e robustas 😉
Dito isso, vamos focar em criar a nossa primeira aplicação usando o módulo HTTP
!
Criando seu primeiro servidor com o módulo HTTP do NodeJS
Vamos começar criando o nosso arquivo app.js
dentro da pasta principal do nosso projeto.
Para importar o módulo HTTP
no seu projeto, basta usar o require
da seguinte forma:
const http = require('http');
O Módulo HTTP
do NodeJS, possui alguns métodos principais:
createServer
: usado para criar uma nova instância de um servidor HTTP
. Dentro dele passamos nossas options
(opções) e os callbacks da requisição, que são chamados assim que o cliente (navegador) acessar o servidor.
listen
: usado para determinar a porta em que o nosso servidor estará sendo executado.
request
: usado para fazer requisições para outros (ou o atual) servidores.
Vamos ver na prática como tudo isso funciona 🙂
App.js
:
/* Aplicação de Testes (app.js) */
const http = require('http');//Importamos o módulo HTTP
const port = 3000;//Definimos a porta que será utilizada, por exemplo: http://localhost:3000
const server = http.createServer((req, res) => {//Criamos um servidor HTTP
//req -> Requisição
//res -> Resposta
res.write('Meu Primeiro Servidor com a Micilini.com');//Escrevemos uma resposta de volta ao navegador do usuário
res.end();//Finalizamos a resposta, pois se não fizermos isso, a requisição ficará em loop (carregando eternamente)
});
server.listen(port, () => {//Iniciamos o servidor na porta definida
console.log(`Servidor rodando em http://localhost:${port}`);//Exibimos uma mensagem no console informando que o servidor está rodando. Essa parte não é mostrada ao usuário
});
Comando simples, não? Mas vamos às explicações 😉
Tudo começa quando você importa o módulo HTTP
para dentro do seu projeto (const http = require('http')
), pois sem ele, você não conseguirá subir um servidor local.
Em seguida, precisamos definir a porta (const port = 3000
) em que queremos rodar o nosso servidor, no meu caso, escolhi a porta 3000
, mas você poderia escolher qualquer porta disponível na sua máquina local.
Observação: Caso a porta 3000
já estiver em uso, você pode escolher as portas 3001
, 3002
, 3003
e assim por diante.
Após a setagem inicial, criamos uma variável (server
) que vai armazenar a instância de createServer
, que representa o nosso servidor. Como você pode perceber, ela recebe duas variáveis:
req
: é um objeto que representa uma solicitação HTTP
recebida pelo servidor, ou seja, uma chamada feita pelo cliente. Ele fornece informações sobre a solicitação do cliente e é uma instância da classe http.IncomingMessage
.
res
: é um objeto que representa a resposta HTTP
que será enviada de volta ao cliente. Ele é uma instância da classe http.ServerResponse
.
Nós próximos tópicos, veremos com uma riquesa de detalhes, alguns métodos e propriedades contidos em cada uma dessas variáveis (req
e res
).
Prosseguindo... usamos o método write
da variável res
, para escrever uma mensagem de volta ao navegador do usuário, que no caso é: Meu Primeiro Servidor com a Micilini.com.
Após isso, usamos o método end
da variável res
, para finalizarmos a resposta, ou seja, fechar a comunicação com o servidor, pois assim como todo bom servidor da web, primeiro ele recebe a resposta do cliente, faz o processamento, responde, e fecha a comunicação... e não fica mantendo uma conexão aberta (ao menos que você esteja usando websockets).
Por fim, usamos o método listen
para fazer com que o nosso servidor fique rodando e escutando todas as solicitações advindas da porta 3000
.
É recomendável que você execute um console.log
dentro do método listen
, pois quando você executar a sua aplicação, o desenvolvedor já vai saber que o servidor está rodando naquela porta.
Para executar esse servidor, com o seu terminal (prompt de comando) aberto na pasta raiz do seu projeto, basta executar:
node ./app.js
Uma mensagem será gerada no console
do seu terminal, indicando que o servidor foi executado com sucesso, e que esta rodando em uma URL específica:
Se você abrir o seu navegador (Google Chrome), e digitar a URL: http://localhost:3000, você receberá a seguinte mensagem:
E aqui está... SEU PRIMEIRO SERVIDOR COM NODEJS 🥳
Outras formas de se criar servidores com o módulo HTTP
Apesar do nosso servidor funcionar, na maioria dos tutoriais da internet, você vai encontrar diversos códigos que te ensinam a criar servidores de uma maneira um pouco diferente, vejamos:
App.js
:
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200; // Define o código de status HTTP
res.setHeader('Content-Type', 'text/plain'); // Define o cabeçalho da resposta
res.end('Hello World\n'); // Envia a resposta e finaliza
});
server.listen(3000, '127.0.0.1', () => {
console.log('Servidor rodando em http://127.0.0.1:3000/');
});
O código acima, não é muuuuito diferente daquilo que você já aprendeu no tópico anterior, com excessão de alguns elementos novos:
statusCode
: cada requisição na web possui um código de status relacionada a ela. Clique aqui para consultar todos os códigos de status que um servidor pode retornar. statusCode
setado como 200
, significa que a requisição foi um sucesso.
setHeader
: cada requisição na web, recebe um cabeçalho e também responde com um cabeçalho. Eles nos ajudam a fazer com que o cliente saiba como tratar os dados recebidos pelo servidor. No caso do código acima, dizemos ao navegador para carregar o conteúdo em formato de texto plano (plain/text).
Clique aqui para consultar todos os possíveis headers que um servidor poderá utilizar.
end
(com resposta?): sim, você também pode executar uma resposta final antes de fechar o servidor.
Por fim, usamos o método listen
passando o número da porta diretamente na função, e de resto nada de muito diferente mudou rs
Parando a execução do nosso servidor
Talvez você já tenha percebido, mas note que alguns serviços que são executados no NodeJS, eles simplesmente não terminam, como é o caso do módulo HTTP
:
Diferente dos outros projeto (app.js
) que criamos em lições anteriores, todos eles excutavam e paravam logo em seguida, dando a oportunidade para o desenvolvedor digitar qualquer outra coisa no terminal:
Infelizmente, esse tipo de coisa, nos obriga a fechar o terminal, ou quem sabe abrir outro terminal para continuar testando nossos códigos.
O módulo HTTP
bloqueia o terminal pois ele é um SERVIDOR, e como um SERVIDOR, ele precisa ficar ligado, sempre escutando as possíveis requisições web que podem acontecer, por esse motivo ele não FECHA.
Para parar a execução, você tem duas alternativas:
1°) Você pode ficar no botão X do seu terminal:
2°) Pressionar (apenas uma vez) as teclas [Ctrl] + [C] dentro do terminal:
O que vai parar a execução do seu servidor, e te dar a possibilidade de digitar novos prompts 🙂
Observação: Depois que o servidor é parado, você não conseguirá mais acessar a url http://localhost:3000, ao menos que execute o servidor novamente (node ./app.js
).
Como retornar arquivos HTML em nosso servidor com NodeJS?
Uma das coisas mais legais que podemos fazer após criar o nosso servidor, é dar a possibilidade dele poder retornar arquivos HTML
, fazendo com que ele atue como a maioria dos servidores da web 🤩
Até porque, grande parte dos servidores da web retornam documentos HTML, você sabia disso? (Espero que sim rs)
Como você já deve ter imaginado, o processo envolve a utilização de mais recursos do módulo HTTP
, como a configuração de um statusCode
(já sabemos como ele funciona) e de um Header
(também já sabemos como funciona).
App_HTML.js
:
/* Aplicação de Testes (app_HTML.js) */
const http = require('http');
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');//Definimos o tipo de conteúdo que será exibido no navegador do usuário, nesse caso, HTML!
res.write('<h1>Meu Primeiro Servidor com a Micilini.com</h1>');//Agora podemos escrever HTML no navegador do usuário =)
res.write('<p>Estamos aprendendo a criar servidores HTTP com Node.js!</p>');//Podemos usar o Write quantas vezes quisermos =)
res.end();
});
server.listen(port, () => {//Iniciamos o servidor na porta definida
console.log(`Servidor rodando em http://localhost:${port}`);
});
No código acima, nós estamos passando no setHeader
a informação text/html
, em que diz para o navegador do usuário que o conteúdo virá com tags HTML
.
E foi isso o que fizemos em ambos os metodos write
, que por sinal, podemos utilizar quantas vezes nós quisermos 🙂
Legal, no comando acima, nós estamos retornando um HTML
que foi escrito dentro do método write
, mas supondo que tenhamos um index.html
, como fazemos para carregar ele?
Bem, nesse caso, precisamos fazer o uso dos outros core modules que aprendemos em lições passadas, que no caso são os módulos fs
e path
:
App_HTMLFile.js
:
// Importa os módulos http e fs
const http = require('http');
const fs = require('fs');
const path = require('path');
const port = 3000;
// Cria o servidor
const server = http.createServer((req, res) => {
// Define o caminho do arquivo index.html
const filePath = path.join(__dirname, 'index.html');
// Lê o arquivo index.html
fs.readFile(filePath, (err, data) => {
if (err) {
res.statusCode = 500; // Erro interno do servidor
res.setHeader('Content-Type', 'text/plain');
res.end('Erro ao ler o arquivo');
return;
}
res.statusCode = 200; // OK
res.setHeader('Content-Type', 'text/html'); // Tipo de conteúdo HTML
res.end(data); // Envia o conteúdo do arquivo para o cliente
});
});
// Inicia o servidor
server.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
No comando acima, nós estamos carregando um arquivo chamado index.html
que existe na mesma pasta raiz do App_HTMLFile.js
.
Além disso, estamos fazendo diversas verificações condicionais no código de modo a retornar um erro (com um statusCode de 500), caso o index.html
não seja encontrado.
Ahhhh, e não se esqueça de criar o seu arquivo HTML
:
index.html
:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meu Primeiro Servidor com a Micilini.com</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
padding: 0;
background-color: #f4f4f4;
color: #333;
}
h1 {
color: #0056b3;
}
p {
font-size: 18px;
}
</style>
</head>
<body>
<h1>Meu Primeiro Servidor com a Micilini.com</h1>
<p>Estamos aprendendo a criar servidores HTTP com Node.js!</p>
</body>
</html>
Ao executar o seu código, você verá um resultado similar a este:
Wooow, incrível não? 🤩
Recuperando parâmetros do tipo Query com o módulo HTTP
Não sei se você já ouviu falar sobre eles, mas parâmetros do tipo query
, são parâmetros que nós podemos passar para uma determinada URL
, de modo a levar uma informação, por exemplo:
http://seusite.com/?usuario=micilini
(usuário é a chave, micilini é o valor)http://google.com/?g=ola%20Mundo
(g é a chave, Ola Mundo é o valor)
No exemplo acima, os query params
atuam como uma especie de estrutura de chave e valor, similar à aquilo que você já conhece no Javascript (lembra dos objetos?).
Além disso, um site pode trabalhar com múltiplos parâmetros, veja um outro exemplo:
http://seusite.com/?produto=iphone&modelo=pro&ano=15
Na URL acima, é como se tivéssemos isso aqui no Javascript:
{
produto: 'iphone',
modelo: 'pro',
ano: '15'
}
Note que todos os parâmetros na URL, acima foram separados pelo &
, mas existem URLs que fazem o uso de &&
, por exemplo:
http://seusite.com/?produto=iphone&&modelo=pro&&ano=15
A verdade, é que parâmetros do tipo Query
, e que são passados pela URL, possuem um segundo nome, onde são mundialmente conhecidos como parâmetros do tipo GET
.
Ou seja, parâmetros que são enviados via método GET
do HTTP
.
Beleza, mas como eu faço para recuperar isso dentro do módulo HTTP?
Bem, no caso do módulo HTTP
, ele não consegue fazer isso sozinho, mas em conjunto com o módulo url
, ele já consegue operar 😉
Para exemplificar isso, vamos criar um servidor que "pode" receber um parâmetro chamado de nome
, e se ele existir, ele retornará uma mensagem de boas vindas relacionado à aquele nome:
app_query.js
:
const http = require('http');
const url = require('url');
const port = 3000;
const server = http.createServer((req, res) => {
// Analisa a URL e obtém os parâmetros de consulta
const parsedUrl = url.parse(req.url, true);
const queryParams = parsedUrl.query;
// Define o tipo de conteúdo como texto plano
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
// Gera a mensagem de boas-vindas
let responseText = '';
if (queryParams.nome) {
responseText = `Olá, ${queryParams.nome}!\nBem-vindo ao nosso servidor!`;
} else {
responseText = 'Olá!\nPor favor, forneça um parâmetro "nome" na URL para uma mensagem personalizada.';
}
// Envia a resposta
res.end(responseText);
});
server.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
No código acima, estamos usando o módulo url
para fazer o parse
da URL que veio na variável req.url
.
Com isso, ele vai conseguir separar os parâmetros do tipo query
, e então salvar dentro da variável queryParams
.
Por fim, criamos uma estrutura condicional, de modo a verificar se a chave nome
(que representa a query nome) está presente na URL, e se sim, ele mostra uma mensagem de boas vindas, se não, ele pede para que o usuário informe o parâmetro nome
na query
🙂
Para testar só seguir a URL: http://localhost:3000/?nome=micilini.
Veja como ficou o resultado final:
Incrível, não?
Agora, vamos supor que a sua URL receba mais de dois parâmetros, como o nome
e a idade
, observe como você poderia fazer essa tratativa:
app_query2.js
:
const http = require('http');
const url = require('url');
const port = 3000;
const server = http.createServer((req, res) => {
// Analisa a URL e obtém os parâmetros de consulta
const parsedUrl = url.parse(req.url, true);
const queryParams = parsedUrl.query;
// Define o tipo de conteúdo como texto plano
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
// Gera a mensagem de resposta com base nos parâmetros
let responseText = '';
if (queryParams.nome && queryParams.idade) {
responseText = `Olá, ${queryParams.nome}!\nVocê tem ${queryParams.idade} anos.\nBem-vindo ao nosso servidor!`;
} else if (queryParams.nome) {
responseText = `Olá, ${queryParams.nome}!\nPor favor, forneça sua idade para uma mensagem completa.`;
} else if (queryParams.idade) {
responseText = `Olá!\nVocê tem ${queryParams.idade} anos.\nPor favor, forneça seu nome para uma mensagem completa.`;
} else {
responseText = 'Olá!\nPor favor, forneça os parâmetros "nome" e "idade" na URL para uma mensagem personalizada.';
}
// Envia a resposta
res.end(responseText);
});
server.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
Para passar os dois parâmetros basta seguir a URL: http://localhost:3000/?nome=micilini&idade=29.
Veja como ficou o resultado final:
Você pode seguir a lógica acima para recuperar inúmeros parâmetros customizados que existem dentro da sua query
😊
Recuperando parâmetros do tipo POST com o módulo HTTP
Nem de parâmetros do tipo query um servidor sobrevive, você sabia disso?
É por esse motivo, que alguns servidores estão devidamente preparados para trabalhar com parâmetros do tipo POST
.
Parâmetros do tipo POST
, geralmente são dados que são enviadas por de baixo dos panos durante uma requisição na web. Não sendo visualmente visíveis na URL 👻
Geralmente esses parâmetros costumam ser enviados por meio de formulários, requisições via API ou por outros front-ends.
Assim como vimos no tópico anterior, o módulo HTTP
não consegue tratar esses parâmetros sozinhos, por isso ele precisa da ajuda de um outro módulo (que ainda não vimos), chamado de querystring
!
O módulo querystring
é um módulo interno do NodeJS, que fornece utilitários para se trabalhar com strings de consulta de URLs, e parsear dados de consultas em uma forma de objeto.
Ele é útil para manipular dados no formato application/x-www-form-urlencoded
, que representa um formato padrão usado por formulários HTML
e alguns tipos de solicitações HTTP POST
.
Além disso, você vai precisar conhecer um pouco mais sobre o método on
da variável req
.
Mas vamos ver como recuperar os dados recebidos via método POST
primeiro 😉
No comando abaixo, vamos criar um servidor que vai aceitar requisições do tipo POST
, e esperar que dois parâmetros sejam enviados: nome
e sobrenome
.
app_post.js
:
const http = require('http');
const querystring = require('querystring');
const port = 3000;
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
if (req.method === 'POST') {
let body = '';
// Receber os dados do corpo da requisição
req.on('data', chunk => {
body += chunk;
});
req.on('end', () => {
// Analisar o corpo da requisição usando querystring
const parsedBody = querystring.parse(body);
const nome = parsedBody.nome;
const sobrenome = parsedBody.sobrenome;
if (nome && sobrenome) {
res.statusCode = 200;
res.end(`Olá, ${nome} ${sobrenome}! Bem-vindo ao servidor!`);
} else {
res.statusCode = 400;
res.end('Nome e sobrenome são necessários!');
}
});
} else {
res.statusCode = 405;
res.end('Método não permitido. Só aceitamos métodos do tipo POST.');
}
});
server.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
No código acima, estamos verificando por meio da variável req
, se a requisição é do tipo POST
(req.method
), e se não for, ele mostra uma mensagem de erro alegando que só aceita requisições do tipo POST
.
Em seguida, por meio do req.on('data', ...)
, estamos capturando todos os dados que estão chegando pra gente pela requisição.
Por fim, quando todos os dados terminarem de vir req.on('end', ...)
, fazemos o parse
dos dados por meio da biblioteca querystring
.
Note que o req.on
retorna um callback 💡
Legal, mas como fazemos para testar esse código?
Você poderia utilizar o POSTMAN ou qualquer outra aplicação de envio de requisições, mas uma forma mais fácil é você copiar o código HTML
abaixo, salvar em um arquivo, abrir esse arquivo HTML
no seu navegador, e fazer o envio normalmente:
envio-via-post.html
:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulário de Dados</title>
</head>
<body>
<h1>Enviar Dados</h1>
<form action="http://localhost:3000/" method="POST">
<label for="nome">Nome:</label>
<input type="text" id="nome" name="nome" required>
<br><br>
<label for="sobrenome">Sobrenome:</label>
<input type="text" id="sobrenome" name="sobrenome" required>
<br><br>
<button type="submit">Enviar</button>
</form>
</body>
</html>
Ao abrir esse arquivo no seu navegador, você verá a seguinte tela:
Basta preencher seu nome e sobrenome, e clicar no botão enviar. Por fim, você será direcionado a URL do servidor local:
A diferença, é que você está acessando a URL via método POST
, tudo isso graças ao formulário HTML
, que conta com um atributo method="POST"
.
Para receber mais dados via método POST
, é só seguir a mesma lógica do código mostrado nesse tópico 😉
Criando um sistema de roteamento simples com o módulo HTTP do NodeJS
Você sabia que todo servidor da web pode contar com um sistema de rotas, também conhecido como um sistema de roteamento?
Sabe quando você entra num determinado site, vai navegando pelas suas páginas, e percebe que a URL daquele site vai se alterando a medida em que os conteúdos de cada página também se alteram?
Então, isso acontece porque o servidor web usa um sistema de rotas, ou roteamento, para determinar qual conteúdo deve ser exibido com base na URL que você está acessando.
Cada rota é basicamente uma correspondência entre um caminho específico na URL, e uma função que gera o conteúdo a ser exibido.
Um e-commerce por exemplo, pode conter diversas páginas que possuem URLs diferentes:
- http://lojavirtual.com.br/produtos
- http://lojavirtual.com.br/sobre
- http://lojavirtual.com.br/carrinho
- http://lojavirtual.com.br/politica-de-privacidade
- http://lojavirtual.com.br/produto/smart-tv-50-polegadas-samsung
Cada uma dessas URLs, vão te levar para partes diferentes do site. A principal funcionalidade que fica responsável por isso, é o sistema de rotas.
No caso do módulo HTTP
do NodeJS, também é possível criar um sistema de rotas, de modo a retornar uma mensagem diferente, dependendo da URL em que o usuário se encontra.
Vamos ver como isso funciona na prática:
app_rotas.js
:
const http = require('http');
const port = 3000;
// Função para tratar a requisição
const requestHandler = (req, res) => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
switch (req.url) {
case '/':
res.statusCode = 200;
res.end('Bem-vindo à página inicial!');
break;
case '/sobre':
res.statusCode = 200;
res.end('Esta é a página sobre nós.');
break;
case '/contato':
res.statusCode = 200;
res.end('Entre em contato conosco através desta página.');
break;
default:
res.statusCode = 404;
res.end('Página não encontrada!');
break;
}
};
// Criar o servidor HTTP
const server = http.createServer(requestHandler);
// Escutar na porta 3000
server.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
No caso do código acima, estamos fazendo o uso do req.url
para pegar a URL que o usuário está acessando.
Em seguida, jogamos essa URL para uma estrutura do SwitchCase
, que por sua vez, ficará responsável por executar as condicionais, e mostrar as devidas mensagens de acordo com a URL que o usuário está acessando.
Nesse caso, se ele acessar a URL http://localhost:3000/ ele abre a página inicial, se ele acessar http://localhost:3000/sobre ele abre a página de sobre, e assim por diante.
Simples, não?
Apesar do código acima funcionar perfeitamente, fazer essa verificação todas dentro de uma estrutura de SwitchCase
deixa o nosso código um pouco mais poluído, não é verdade?
Que tal modularizar o código, de modo a criar uma função específica para cada página?
app_rotas_modularizado.js
:
const http = require('http');
const port = 3000;
// Funções para lidar com cada rota
const handleHome = (res) => {
res.statusCode = 200;
res.end('Bem-vindo à página inicial!');
};
const handleSobre = (res) => {
res.statusCode = 200;
res.end('Esta é a página sobre nós.');
};
const handleContato = (res) => {
res.statusCode = 200;
res.end('Entre em contato conosco através desta página.');
};
const handleNotFound = (res) => {
res.statusCode = 404;
res.end('Página não encontrada!');
};
// Função para tratar a requisição
const requestHandler = (req, res) => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
switch (req.url) {
case '/':
handleHome(res);
break;
case '/sobre':
handleSobre(res);
break;
case '/contato':
handleContato(res);
break;
default:
handleNotFound(res);
break;
}
};
// Criar o servidor HTTP
const server = http.createServer(requestHandler);
// Escutar na porta 3000
server.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
O funcionamento do código acima é o mesmo, a diferença é que criamos funções separadas para tornar o código mais limpo, e mais fácil de se manter.
Veja como ficou o resultado final:
Sabendo como funciona o sistema de rotas no NodeJS, que tal aplicar os conceitos que você aprendeu em tópicos anteriores desta lição?
Como exercício, gostaria que você fizesse o seguinte:
- Cria uma rota específica para receber dados via método GET.
- Crie uma rota específica para receber dados via método POST.
- Crie uma rota específicia para carregar um determinado arquivo HTML.
Realizando requisições externas com o módulo http e https
Você sabia que o módulo http
, e também o módulo https
(usado para conexões seguras), é capaz de realizar requisições externas de modo a retornar dados de APIs de terceiros?
Não, então veja como isso pode ser feito:
app_api_externa.js
:
const http = require('http');
const https = require('https');
// Função para fazer a requisição HTTP para a API
const fetchUsers = () => {
return new Promise((resolve, reject) => {
https.get('https://jsonplaceholder.typicode.com/users', (response) => {
let data = '';
// Receber dados do corpo da resposta
response.on('data', chunk => {
data += chunk;
});
// Quando a resposta estiver completa, resolver a Promise
response.on('end', () => {
try {
const users = JSON.parse(data);
resolve(users);
} catch (error) {
reject(error);
}
});
}).on('error', (error) => {
reject(error);
});
});
};
// Função principal para iniciar o servidor
const startServer = () => {
const server = http.createServer(async (req, res) => {
if (req.url === '/fetch-users' && req.method === 'GET') {
try {
const users = await fetchUsers();
console.log('Nomes dos usuários:');
users.forEach(user => {
console.log(user.name);
});
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('Nomes dos usuários foram exibidos no console.');
} catch (error) {
console.error('Erro ao buscar usuários:', error);
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('Erro ao buscar usuários.');
}
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Rota não encontrada!');
}
});
server.listen(3000, () => {
console.log('Servidor rodando na porta 3000');
});
};
startServer();
Para acessar, basta seguir o link http://localhost:3000/fetch-users.
Os nomes retornados pela API, estão sendo mostrados no console da sua aplicação da seguinte forma:
A função fetchUsers
, faz uma requisição GET
para a API JSONPlaceholder usando o módulo https
, uma vez que a API faz o uso do https://
.
Em seguida, a resposta é convertida atráves do método https.get
, em uma Promise
para facilitar o uso de funções assíncronas (async/await
). E então, processa a resposta da API e resolve com a lista de usuários.
Já a função startServer
, é um outro jeito que nós temos para criar um servidor HTTP
(a diferença dos anteriores, é que aqui nós encapsulamos toda logíca dentro de uma função).
Quando o usuário abre a rota /fetch-users
, uma requisição é feita a API, de modo a retornar os nomes dos usuários e exibí-los no console.
Observe um outro exemplo, em que estamos fazendo uma solicitação HTTP
usando o http.request()
:
const http = require('http');
const options = {
hostname: 'www.example.com',
port: 80,
path: '/',
method: 'GET'
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Resposta completa:', data);
});
});
req.on('error', (e) => {
console.error(`Problema com a solicitação: ${e.message}`);
});
req.end();
Conhecendo os métodos principais do módulo HTTP
O módulo HTTP
do NodeJS, possui inúmeros métodos e propriedades que nos ajudam a criar servidores web de forma mais robusta.
Veremos com mais detalhes o funcionamento de cada um deles nos próximos tópicos 😉
http.createServer
Ele cria um novo servidor HTTP
que pode ser configurado com opções personalizadas e um requestListener
, que é chamado sempre quando uma soliticação HTTP
é recebida.
options (opcional)
: um objeto que pode conter opções como maxHeaderSize
, timeout
, headersTimeout
, etc.
requestListener (opcional)
: uma função que é chamada para lidar com solicitações. Esta função tem a assinatura (req
, res
).
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=UTF-8');
res.end('Olá Mundo\n');
});
server.listen(3000, '127.0.0.1', () => {
console.log('Servidor Rodando em http://127.0.0.1:3000/');
});
http.request
Ele faz uma solicitação HTTP
como se fosse um cliente chamando um servidor.
options
: um objeto com opções para a solicitação, como hostname
, port
, path
, method
, headers
, etc.
callback (opcional)
: uma função chamada quando a resposta é recebida. Tem a assinatura (response
).
const http = require('http');
const options = {
hostname: 'www.example.com',
port: 80,
path: '/',
method: 'GET'
};
const req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
});
req.end();
http.get
Ele faz uma solicitação do tipo GET
, que é a forma mais simples de fazer uma requisição.
options
: um objeto com opções para a solicitação, como hostname
, port
, path
, headers
, etc.
callback (opcional)
: Uma função chamada quando a resposta é recebida. Tem a assinatura (response
).
const http = require('http');
http.get('http://www.example.com/', (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log(data);
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
Observação: o módulo http
não conta com um método http.post
para fazer requisição do tipo POST
. Em vez disso, você usao comando http.request
, e define o método como POST
nas opções da solicitação, por exemplo:
const http = require('http');
// Dados a serem enviados na requisição POST
const postData = JSON.stringify({
name: 'John Doe',
email: 'john.doe@example.com'
});
// Opções para a requisição POST
const options = {
hostname: 'jsonplaceholder.typicode.com',
port: 80,
path: '/posts', // Endereço da API que aceita POST
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};
// Fazer a requisição POST
const req = http.request(options, (res) => {
let responseBody = '';
console.log(`Status Code: ${res.statusCode}`);
console.log(`Headers: ${JSON.stringify(res.headers)}`);
// Receber dados do corpo da resposta
res.on('data', (chunk) => {
responseBody += chunk;
});
// Quando a resposta estiver completa
res.on('end', () => {
console.log('Resposta Completa:');
console.log(responseBody);
});
});
// Tratar erros na requisição
req.on('error', (e) => {
console.error(`Problema com a requisição: ${e.message}`);
});
// Enviar os dados na requisição POST
req.write(postData);
// Finalizar a requisição
req.end();
No código acima, estamos fazendo o uso da API JSONPlaceholder para fazer solicitações via POST
.
Para saber mais detalhes sobre o funcionamento do módulo HTTP
, não deixe de consultar a documentação da biblioteca.
Variável REQ
A variável req
é um objeto que representa a solicitação HTTP
recebida pelo servidor.
Ela representa uma instância da classe incomingMessage
do módulo HTTP
, e conta com as seguintes propriedades.
1) req.method
Retorna o método HTTP
da solicitação em questão. Pode ser GET
, POST
, PUT
, DELETE
e entre outros.
console.log(req.method); // 'GET', 'POST', etc.
2) req.url
Retorna a URL da solicitação em questão. Incluí também o caminho e a consulta.
console.log(req.url); // '/path?name=value'
3) req.headers
Retorna todos os cabeçalhos da soliticação. Lembrando que os nomes dos cabeçalhos são convertidos para minúsculas.
console.log(req.headers['content-type']); // 'text/html'
4) req.query
Normalmente, a propriedade query
não está disponível diretamente em req
. Você teria que usar um módulo como querystring
ou url
para analisá-lo.
Apesar disso, a query
retorna as querys
que podem existir na sua URL:
const url = require('url');
const queryObject = url.parse(req.url,true).query;
console.log(queryObject); // { name: 'value' }
5) req.body
Retorna o corpo da requisição, por padrão, ele não é parseado automaticamente, por isso você precisa de um middleware
como o body-parser
existente na biblioteca Express
.
//O código abaixo faz o uso da biblioteca Express!
app.use(express.json());
app.post('/', (req, res) => {
console.log(req.body); // { key: 'value' }
});
Atenção: Ainda vamos entrar no uso de middlewares
, body-parser
e Express
em lições futuras, fique tranquilo 😉
6) req.connection
Retorna um objeto que representa informações detalhadas da rede.
console.log(req.connection.remoteAddress); // IP do cliente
Variável RES
A variável res
, é um objeto que representa a resposta HTTP
que será enviada de volta ao cliente.
Ela é uma instância da classe ServerResponde
, vamos analisar seus principais métodos e propriedades abaixo:
1) res.statusCode
Define o status HTTP
que será enviado de volta ao cliente.
res.statusCode = 200; // OK
res.statusCode = 404; // Not Found
2) res.statusMessage
Define a mensagem de status relacionada ao código HTTP
.
res.statusMessage = 'OK'; // Ou outro texto descritivo
3) res.setHeader
Define um cabeçalho na resposta de volta ao cliente.
res.setHeader('Content-Type', 'text/html');
4) res.write
Envia um pedaço de dados de volta ao cliente. Pode ser chamado diversas vezes.
res.write('Olá ');
res.write('Mundo!');
5) res.end
Finaliza a resposta, podendo enviar quaisquer dados restantes para o cliente.
res.end('Tchau!');
6) res.writeHead
Envia o cabeçalho de resposta com o código de status. Representa uma alternativa ao uso do statusCode
.
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World');
Eu preciso me especializar no módulo HTTP?
Apesar do módulo HTTP
estar presente na maioria das aplicações feitas com NodeJS, você não precisa se especializar nele.
Pois como você mesmo verá em aulas futuras, a maioria das aplicações preferem fazer o uso de bibliotecas (como é o caso do Express) para subirem servidores de maneira mais rápida e fácil.
Dificilmente você encontrará um projeto que faz o uso do módulo HTTP
sem a necessidade de uma outra biblioteca, é muito raro mesmo!
Sendo assim, só crie servidores web diretamente com o módulo HTTP
, caso você precise fazer algo muito específico na sua aplicação, tipo de coisa que nenhuma biblioteca (Express, Hapi...) seja capaz de fazer.
No más, como sugestão, recomendo você se especializar na utilização de algumas bibliotecas como Express
, Hapi
e entre outras, pois é assim que a maioria dos projetos constrõem seus servidores web 🙂
Arquivos da lição
Os arquivos que você viu durante o decorrer desta lição, podem ser encontrados neste link.
Conclusão
Ufa.... esse módulo HTTP
deu um trabalho, né verdade? 😮💨
E olha que nem vimos 100% de tudo o que ele pode nos oferecer 😂
No más, basta dar uma olhada na documentação desse módulo, e mergulhar no seu mar de possíbilidades 😉
Até a próxima lição!