Aprenda sobre módulo 'http': criando um servidor web básico
45 min
Aula 6 de 6
Módulo 'http': Criando um Servidor Web Básico 🚀
Olá, futuro desenvolvedor Node.js! 👋 Nesta aula prática, vamos mergulhar no coração da criação de servidores web com Node.js: o módulo http. Este módulo é a base para qualquer aplicação web Node.js, seja um microserviço simples ou a espinha dorsal de um framework como o Express.js.
Com o http module, você aprenderá a:
Iniciar um servidor que escuta requisições.
Processar requisições HTTP recebidas.
Enviar respostas HTTP de volta aos clientes.
Vamos colocar a mão na massa e construir nosso primeiro servidor web do zero! 💻
1. Introdução ao Módulo http 🌐
O módulo http do Node.js fornece funcionalidades para criar servidores HTTP e clientes HTTP. Ele é fundamental para qualquer tipo de comunicação web em Node.js. Ao usar este módulo, você tem controle total sobre o processo de requisição e resposta HTTP, permitindo construir servidores altamente personalizados.
Por que é importante?
Mesmo que você venha a usar frameworks como Express.js ou Koa.js no futuro, entender como o módulo http funciona por baixo dos panos é crucial. Isso lhe dará uma base sólida para depurar, otimizar e compreender o que realmente acontece quando uma requisição chega ao seu servidor.
2. Explicação Detalhada: Construindo um Servidor 🛠️
Para criar um servidor web básico com o módulo http, seguimos alguns passos essenciais:
Importar o módulo http: O primeiro passo é sempre importar o módulo que queremos usar.
Criar o Servidor: Usamos o método http.createServer() que aceita uma função de callback. Esta função será executada toda vez que uma requisição HTTP for recebida pelo servidor.
A função de callback recebe dois argumentos:
request (ou req): Um objeto IncomingMessage que contém todas as informações da requisição do cliente (URL, método HTTP, cabeçalhos, corpo, etc.).
response (ou res): Um objeto ServerResponse que usamos para enviar a resposta de volta ao cliente (cabeçalhos, status, corpo da resposta).
Definir a Resposta: Dentro da função de callback, você define como o servidor deve responder.
res.statusCode: Define o código de status HTTP (ex: 200 para OK, 404 para Não Encontrado).
res.setHeader(): Define os cabeçalhos da resposta (ex: Content-Type para indicar o tipo de conteúdo).
res.end(): Envia o corpo da resposta e finaliza a comunicação com o cliente. É essencial chamar res.end() para que o cliente receba a resposta.
Fazer o Servidor Escutar: O método server.listen() inicia o servidor e o faz "escutar" em uma porta específica do seu computador. Ele também pode aceitar um endereço IP opcional.
Vamos ver um exemplo prático.
Exemplo Oficial (Baseado na Documentação Node.js) 📚
Este é um exemplo clássico de um servidor "Hello World" usando o módulo http, muito similar ao encontrado na documentação oficial do Node.js.
// server.jsconst http = require('http');const hostname = '127.0.0.1'; // Endereço IP localconst port = 3000; // Porta onde o servidor vai escutar// Cria o servidorconst server = http.createServer((req, res) => { // Define o código de status HTTP 200 (OK) res.statusCode = 200; // Define o cabeçalho Content-Type para texto simples res.setHeader('Content-Type', 'text/plain'); // Envia a resposta "Olá, Mundo!" e finaliza a comunicação res.end('Olá, Mundo!\n');});// Faz o servidor escutar na porta e hostname definidosserver.listen(port, hostname, () => { console.log(`Servidor rodando em http://${hostname}:${port}/`); console.log('Para parar o servidor, pressione Ctrl+C');});
Como rodar este código:
Salve o código acima em um arquivo chamado server.js.
Abra seu terminal no diretório onde salvou o arquivo.
Execute o comando: node server.js
Ab.ra seu navegador e acesse http://localhost:3000. Você verá a mensagem "Olá, Mundo!".
No terminal, você verá o log Servidor rodando em http://127.0.0.1:3000/.
Entendendo os objetos request e response
request (req):
req.url: A URL da requisição (ex: /, /about, /api/users).
req.method: O método HTTP da requisição (ex: GET, POST, PUT, DELETE).
req.headers: Um objeto contendo todos os cabeçalhos da requisição.
req.on('data', ...) e req.on('end', ...): Usados para ler o corpo da requisição (útil para POST e PUT).
response (res):
res.statusCode: Define o código de status HTTP.
res.setHeader(name, value): Define um cabeçalho HTTP.
res.writeHead(statusCode, headers): Uma forma mais concisa de definir status e múltiplos cabeçalhos de uma vez.
res.write(chunk): Escreve um pedaço do corpo da resposta. Pode ser chamado múltiplas vezes.
res.end([data]): Finaliza a resposta. Opcionalmente, pode enviar o último pedaço de dados.
Exemplo com Roteamento Básico e Diferentes Métodos HTTP
Vamos aprimorar nosso servidor para responder de forma diferente com base na URL (req.url) e no método HTTP (req.method).
// advanced-server.jsconst http = require('http');const hostname = '127.0.0.1';const port = 3000;const server = http.createServer((req, res) => { // Log da requisição para fins de depuração console.log(`Requisição recebida: ${req.method} ${req.url}`); // Definindo o cabeçalho Content-Type padrão para JSON (vamos enviar JSON na maioria dos casos) res.setHeader('Content-Type', 'application/json'); if (req.url === '/') { // Rota para a página inicial if (req.method === 'GET') { res.statusCode = 200; res.end(JSON.stringify({ message: 'Bem-vindo à API inicial!' })); } else { res.statusCode = 405; // Método não permitido res.end(JSON.stringify({ error: 'Método não permitido para esta rota.' })); } } else if (req.url === '/users') { // Rota para usuários if (req.method === 'GET') { res.statusCode = 200; res.end(JSON.stringify([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }])); } else if (req.method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk.toString(); // Converte Buffer para string }); req.on('end', () => { try { const newUser = JSON.parse(body); console.log('Novo usuário recebido:', newUser); res.statusCode = 201; // Criado res.end(JSON.stringify({ message: 'Usuário criado com sucesso!', user: newUser })); } catch (error) { res.statusCode = 400; // Requisição inválida res.end(JSON.stringify({ error: 'Corpo da requisição inválido.' })); } }); } else { res.statusCode = 405; res.end(JSON.stringify({ error: 'Método não permitido para esta rota.' })); } } else { // Rota não encontrada res.statusCode = 404; res.end(JSON.stringify({ error: 'Página não encontrada.' })); }});server.listen(port, hostname, () => { console.log(`Servidor rodando em http://${hostname}:${port}/`);});
Você deve ver a resposta JSON no terminal e o log Novo usuário recebido: no terminal onde o servidor está rodando.
Sobre Integração com Múltiplas Tecnologias 🤝
Nesta aula, nosso foco é puramente no módulo http do Node.js, que é a camada mais fundamental para construir servidores web. Ferramentas e frameworks como o Express.js, que você provavelmente usará em projetos maiores, são construídos sobre este módulo http, abstraindo muitas das complexidades que estamos explorando aqui (como roteamento manual, parsing de corpo de requisição, etc.).
Portanto, não há "integração" de http com outras tecnologias neste contexto, pois o http é a base. Em aulas futuras, quando abordarmos frameworks, veremos como eles simplificam o trabalho que estamos fazendo manualmente agora.
3. Exercícios/Desafios Práticos 💪
Agora é a sua vez de praticar! Crie um novo arquivo JavaScript para cada desafio.
Desafio 1: Servidor de Páginas Simples 📄
Crie um servidor que responda com diferentes mensagens HTML para URLs específicas.
Tarefas:
Crie um arquivo desafio1.js.
Inicie um servidor HTTP na porta 4000.
Se a requisição for para /, responda com um HTML simples contendo um título <h1>Bem-vindo!</h1> e um parágrafo Estamos na página inicial.. Defina o Content-Type como text/html.
Se a requisição for para /contato, responda com um HTML contendo <h1>Entre em Contato</h1> e um formulário de contato simulado (apenas HTML, sem funcionalidade).
Para qualquer outra URL, responda com um 404 Not Found e um HTML <h1>Página Não Encontrada</h1>.
Dica: Use res.setHeader('Content-Type', 'text/html'); e strings HTML para res.end().
// Exemplo de estrutura para o desafio 1 (não é a solução completa!)const http = require('http');// ...const server = http.createServer((req, res) => { if (req.url === '/') { res.statusCode = 200; res.setHeader('Content-Type', 'text/html'); res.end('<h1>Bem-vindo!</h1><p>Estamos na página inicial.</p>'); } // ... continue com as outras rotas});// ...
Desafio 2: Servidor de API de Produtos 📦
Crie um servidor que simule uma API de produtos, respondendo a requisições GET e POST com dados JSON.
Tarefas:
Crie um arquivo desafio2.js.
Inicie um servidor HTTP na porta 5000.
Mantenha um array de objetos JavaScript para simular um banco de dados de produtos (ex: [{ id: 1, name: 'Laptop', price: 1200 }]).
Rota /products:
Para requisições GET, retorne todos os produtos como JSON.
Para requisições POST, leia o corpo da requisição (JSON), adicione o novo produto ao array (dê um id único, ex: produtos.length + 1), e retorne o produto criado com status 201 Created. Lembre-se de tratar o corpo da requisição assincronamente (req.on('data'), req.on('end')) e fazer o JSON.parse().
Rota /products/:id (ex: /products/1):
Para requisições GET, retorne o produto com o id correspondente como JSON. Se não encontrar, retorne 404 Not Found.
Dica: Você precisará parsear req.url para extrair o ID. Uma forma simples é req.url.split('/')[2].
Para outras rotas, retorne 404 Not Found com uma mensagem JSON de erro.
Defina o Content-Type como application/json para todas as respostas.
// Exemplo de estrutura para o desafio 2 (não é a solução completa!)const http = require('http');let products = [ { id: 1, name: 'Smartphone', price: 800 }, { id: 2, name: 'Tablet', price: 450 }];const server = http.createServer((req, res) => { res.setHeader('Content-Type', 'application/json'); if (req.url === '/products') { if (req.method === 'GET') { res.statusCode = 200; res.end(JSON.stringify(products)); } else if (req.method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { try { const newProduct = JSON.parse(body); newProduct.id = products.length ? Math.max(...products.map(p => p.id)) + 1 : 1; products.push(newProduct); res.statusCode = 201; res.end(JSON.stringify(newProduct)); } catch (error) { res.statusCode = 400; res.end(JSON.stringify({ error: 'Invalid JSON body' })); } }); } else { res.statusCode = 405; // Method Not Allowed res.end(JSON.stringify({ error: 'Method not allowed' })); } } else if (req.url.startsWith('/products/')) { const productId = parseInt(req.url.split('/')[2]); const product = products.find(p => p.id === productId); if (req.method === 'GET') { if (product) { res.statusCode = 200; res.end(JSON.stringify(product)); } else { res.statusCode = 404; res.end(JSON.stringify({ error: 'Product not found' })); } } else { res.statusCode = 405; res.end(JSON.stringify({ error: 'Method not allowed for this route' })); } } else { res.statusCode = 404; res.end(JSON.stringify({ error: 'Not Found' })); }});server.listen(5000, () => { console.log('API de Produtos rodando em http://localhost:5000');});
4. Resumo e Próximos Passos 🔚
Parabéns! 🎉 Você deu os primeiros passos cruciais na construção de servidores web com Node.js usando o módulo http. Você aprendeu a:
Importar e usar o módulo http.
Criar um servidor básico com http.createServer().
Entender os objetos request e response.
Definir cabeçalhos (res.setHeader()) e códigos de status (res.statusCode).
Enviar respostas com res.end().
Fazer roteamento básico com base em req.url e req.method.
Lidar com corpos de requisição (POST).
Este conhecimento é a base de tudo que você fará em desenvolvimento web com Node.js.
Próximos Passos:
Módulo fs (File System): Aprenda a ler e escrever arquivos, o que é essencial para servir arquivos estáticos (HTML, CSS, JS, imagens) ou para persistência de dados.
Módulo url: Para um parseamento mais robusto de URLs, incluindo parâmetros de query string.
Frameworks Web (Express.js, Koa.js): Uma vez que você se sentir confortável com o http module, explore frameworks que abstraem e simplificam grande parte do trabalho manual que fizemos hoje, oferecendo roteamento mais avançado, middlewares, etc.
Manipulação de Erros: Como lidar com erros de forma mais robusta no seu servidor.
Continue praticando e explorando! A jornada Node.js é fascinante. ✨