Node.js: Módulo HTTP
Última atualização: 2026-08-26
Bob precisava validar rapidamente uma ideia de API, mas não queria configurar um projeto Express completo; por isso, usou o módulo HTTP nativo para colocar um servidor de API em funcionamento com apenas 20 linhas de código. Desde o tratamento dos métodos de solicitação e a análise de caminhos de URL até o retorno de dados JSON e a definição de códigos de status, Bob percebeu que, depois de compreender os princípios subjacentes, usar uma estrutura de trabalho se tornou, na verdade, muito mais fácil.
1. O que você vai aprender
- Use
http.createServer/server.listenpara criar um servidor HTTP - Ler as propriedades principais (métodos / URL / cabeçalhos) do objeto
request - Use o objeto
responsepara enviar uma resposta (writeHead / end / statusCode) - Use
new URL()para analisar caminhos route e parâmetros de consulta query - Tratamento de solicitações GET e parâmetros de consulta
- Tratamento de solicitações POST e coleta do corpo das solicitações
- Definir o Content-Type e os cabeçalhos de resposta personalizados
- Os significados e casos de uso dos códigos de status HTTP mais comuns
2. Criando seu primeiro servidor HTTP
http.createServer Aceita uma função de callback que é acionada sempre que uma solicitação é recebida. A função de callback recebe dois parâmetros: request (o objeto da solicitação) e response (o objeto da resposta). server.listen especifica a porta de escuta.
▶ Exemplo: Minimizando um servidor HTTP
const http = require('http');
const server = http.createServer((req, res) => {
res.end('Hello, World!');
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
node server.js
Server running at http://localhost:3000/
Basta acessar http://localhost:3000/ no seu navegador para visualizar Hello, World!.
3. O ciclo de vida da solicitação e resposta HTTP
Toda interação HTTP segue o processo de Solicitação → Roteamento → Processamento → Resposta; compreender esse ciclo de vida é a base para a criação de serviços web.
flowchart LR
A["Client"] -->|"Send Request"| B["request Object<br/>method / url / headers"]
B --> C["Routing Resolution<br/>pathname + searchParams"]
C --> D{"Request Method?"}
D -->|GET| E["Read Query Parameters"]
D -->|POST / PUT| F["Collect the request body"]
E --> G["Business Processing"]
F --> G
G --> H["response Object<br/>statusCode / headers / body"]
H -->|"Return Response"| A
4. Propriedades principais do objeto request
request O objeto contém todas as informações da solicitação enviadas pelo cliente; as três propriedades mais utilizadas são method, url e headers.
| Propriedade / Método | Tipo | Descrição | Exemplo de valor |
|---|---|---|---|
req.method |
string | Método da solicitação | 'GET', 'POST' |
req.url |
string | Caminho da solicitação (incluindo a string de consulta) | '/api/users?id=1' |
req.headers |
objeto | Objeto de cabeçalho da solicitação | { 'content-type': 'application/json' } |
req.httpVersion |
string | versão do protocolo HTTP | '1.1' |
req.socket |
objeto | objeto de soquete subjacente | — |
▶ Exemplo: Informações sobre solicitações de impressão
const http = require('http');
const server = http.createServer((req, res) => {
console.log(`Method: ${req.method}`);
console.log(`URL: ${req.url}`);
console.log(`Content-Type: ${req.headers['content-type'] || 'N/A'}`);
res.end('Check your terminal for request info.');
});
server.listen(3000);
Envie uma solicitação de teste usando o curl:
curl -X POST http://localhost:3000/api/data -H "Content-Type: application/json"
Method: POST
URL: /api/data
Content-Type: application/json
5. Métodos principais do objeto response
response Este objeto é usado para enviar dados de resposta ao cliente, incluindo o código de status, os cabeçalhos de resposta e o corpo da resposta.
| Método / Propriedade | Descrição | Exemplo |
|---|---|---|
res.writeHead(statusCode, headers) |
Como gravar códigos de status e vários cabeçalhos de resposta em uma única operação | res.writeHead(200, { 'Content-Type': 'text/plain' }) |
res.statusCode = n |
Definir código de status individualmente | res.statusCode = 404 |
res.setHeader(name, value) |
Definir um único cabeçalho de resposta | res.setHeader('Content-Type', 'application/json') |
res.write(data) |
Gravar os dados do corpo da resposta (pode ser chamado várias vezes) | res.write('partial') |
res.end(data) |
Enviar o corpo da resposta e encerrar a resposta | res.end('done') |
res.writeHead Após ser chamado, em seguida res.end() |
Enviar dados armazenados no buffer | — |
▶ Exemplo: Retornar uma resposta JSON
const http = require('http');
const server = http.createServer((req, res) => {
const data = { message: 'Success', timestamp: Date.now() };
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
});
server.listen(3000);
curl http://localhost:3000/
{"message":"Success","timestamp":1719792000000}
6. Resolução de roteamento de URLs
req.url contém o caminho completo da solicitação e a string de consulta. O uso de new URL() facilita a separação entre o nome do caminho e os parâmetros de consulta, permitindo o roteamento baseado em caminho.
▶ Exemplo: Roteamento baseado em caminho
const http = require('http');
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const pathname = url.pathname;
res.writeHead(200, { 'Content-Type': 'text/plain' });
if (pathname === '/') {
res.end('Home Page');
} else if (pathname === '/about') {
res.end('About Page');
} else if (pathname === '/api/status') {
res.end('OK');
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
server.listen(3000);
7. Solicitações GET e parâmetros de consulta
Os parâmetros de uma solicitação GET estão incluídos na string de consulta da URL, e é possível recuperar os pares chave-valor diretamente usando url.searchParams.
▶ Exemplo: Análise de parâmetros de consulta
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method !== 'GET') {
res.writeHead(405, { 'Content-Type': 'text/plain' });
res.end('Method Not Allowed');
return;
}
const url = new URL(req.url, `http://${req.headers.host}`);
const name = url.searchParams.get('name') || 'Guest';
const page = url.searchParams.get('page') || '1';
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ name, page }));
});
server.listen(3000);
curl "http://localhost:3000/?name=Bob&page=3"
{"name":"Bob","page":"3"}
Observação:
searchParams.get()sempre retorna uma string; portanto, é necessário convertê-la manualmente em um número ou outro tipo.
8. Solicitações POST e coleta do corpo da solicitação
Os dados das solicitações POST são transmitidos por meio do corpo da solicitação. O objeto request é um fluxo legível; é necessário monitorar o evento data para coletar blocos de dados e monitorar o evento end para processar os dados completos.
▶ Exemplo: Como coletar o corpo da solicitação POST
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/api/users') {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
try {
const data = JSON.parse(body);
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: 1, ...data }));
} catch (e) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Invalid JSON' }));
}
});
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
server.listen(3000);
curl -X POST http://localhost:3000/api/users -H "Content-Type: application/json" -d "{\"name\":\"Bob\",\"age\":30}"
{"id":1,"name":"Bob","age":30}
9. Tipo de conteúdo e cabeçalhos de resposta
Content-Type Este é um dos cabeçalhos de resposta mais importantes na comunicação HTTP, pois especifica o formato dos dados do corpo da resposta para o cliente. Se for configurado incorretamente, o cliente não conseguirá analisar os dados corretamente.
| Tipo de conteúdo | Finalidade | Descrição |
|---|---|---|
text/plain |
Texto simples | O tipo de texto mais básico, sem formatação |
text/html |
Página HTML | O navegador exibe isso como uma página da web |
application/json |
Dados JSON | O formato de resposta mais utilizado em APIs |
application/x-www-form-urlencoded |
Dados do formulário | Formato padrão de envio do formulário |
multipart/form-data |
Envio de arquivos | Envio de formulário com arquivos |
application/xml |
Dados XML | API SOAP ou interface legada |
text/css |
Folha de estilo CSS | Folha de estilo |
application/octet-stream |
Fluxo binário | Cenários de download de arquivos |
▶ Exemplo: O efeito de diferentes tipos de conteúdo para os mesmos dados
const http = require('http');
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
if (url.pathname === '/plain') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('<h1>This is plain text</h1>');
} else if (url.pathname === '/html') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>This is HTML</h1>');
} else if (url.pathname === '/json') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'This is JSON' }));
}
});
server.listen(3000);
Quando você acessa /plain, o navegador exibe a aba do código-fonte; quando você acessa /html, o navegador exibe o título principal; e quando você acessa /json, o navegador exibe dados JSON.
10. Referência rápida aos códigos de status HTTP
Um código de status é uma representação padronizada da resposta do servidor a uma solicitação; o cliente determina sua próxima ação com base nesse código de status.
| Código de status | Categoria | Significado | Situações comuns |
|---|---|---|---|
| 200 | 2xx Sucesso | OK | A solicitação GET retornou dados com sucesso |
| 201 | 2xx Sucesso | Criado | Recurso POST criado com sucesso |
| 204 | 2xx Sucesso | Sem conteúdo | Exclusão bem-sucedida, nenhum conteúdo retornado |
| 301 | Redirecionamento 3xx | Movido permanentemente | Redirecionamento permanente para o novo URL |
| 302 | Redirecionamento 3xx | Encontrado | Redirecionamento temporário |
| 304 | Redirecionamento 3xx | Não modificado | Acertou no cache; não é necessário retransmitir |
| 400 | Erro do cliente 4xx | Solicitação inválida | Formato inválido do parâmetro da solicitação |
| 401 | Erro 4xx do cliente | Não autorizado | Não autenticado; é necessário fazer login |
| 403 | Erro 4xx do cliente | Acesso proibido | Autenticado, mas sem permissões |
| 404 | Erro 4xx do cliente | Não encontrado | A rota ou o recurso não existe |
| 405 | Erro do cliente 4xx | Método não permitido | O método da solicitação não é permitido |
| 500 | Erro 5xx do servidor | Erro interno do servidor | Erro interno do servidor |
| 502 | Erro 5xx do servidor | Gateway inválido | O gateway/proxy recebeu uma resposta inválida |
| 503 | Erro 5xx do servidor | Serviço indisponível | Serviço temporariamente indisponível |
▶ Exemplo: Retornando códigos de status diferentes com base em condições
const http = require('http');
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const id = url.searchParams.get('id');
if (!id) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Missing id parameter' }));
} else if (id === '0') {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'User not found' }));
} else {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id, name: 'Bob' }));
}
});
server.listen(3000);
11. Exemplo abrangente: um servidor de API REST simples
Combine todos os conceitos abordados até agora para criar um servidor de API REST que suporte rotas GET/POST, respostas em JSON e análise de parâmetros de consulta. Mantenha uma lista de usuários na memória e ofereça suporte a três operações: consultar todos os usuários, consultar um único usuário e criar um usuário.
const http = require('http');
const users = [
{ id: 1, name: 'Bob', email: 'bob@example.com' },
{ id: 2, name: 'Alice', email: 'alice@example.com' },
];
let nextId = 3;
function parseBody(req) {
return new Promise((resolve, reject) => {
let body = '';
req.on('data', (chunk) => { body += chunk.toString(); });
req.on('end', () => {
try { resolve(JSON.parse(body)); }
catch (e) { reject(e); }
});
req.on('error', reject);
});
}
function sendJSON(res, statusCode, data) {
res.writeHead(statusCode, {
'Content-Type': 'application/json',
'X-Powered-By': 'Node.js',
});
res.end(JSON.stringify(data));
}
const server = http.createServer(async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const pathname = url.pathname;
// GET /api/users
if (req.method === 'GET' && pathname === '/api/users') {
const limit = parseInt(url.searchParams.get('limit')) || 10;
sendJSON(res, 200, users.slice(0, limit));
return;
}
// GET /api/users/:id
if (req.method === 'GET' && pathname.startsWith('/api/users/')) {
const id = parseInt(pathname.split('/').pop());
const user = users.find((u) => u.id === id);
if (!user) {
sendJSON(res, 404, { error: 'User not found' });
} else {
sendJSON(res, 200, user);
}
return;
}
// POST /api/users
if (req.method === 'POST' && pathname === '/api/users') {
try {
const data = await parseBody(req);
if (!data.name || !data.email) {
sendJSON(res, 400, { error: 'name and email are required' });
return;
}
const newUser = { id: nextId++, name: data.name, email: data.email };
users.push(newUser);
sendJSON(res, 201, newUser);
} catch (e) {
sendJSON(res, 400, { error: 'Invalid JSON body' });
}
return;
}
// 404 fallback
sendJSON(res, 404, { error: 'Route not found' });
});
server.listen(3000, () => {
console.log('REST API server running at http://localhost:3000/');
});
Teste todas as interfaces:
# Query All Users
curl http://localhost:3000/api/users
# Query a Single User
curl http://localhost:3000/api/users/1
# Create a New User
curl -X POST http://localhost:3000/api/users -H "Content-Type: application/json" -d "{\"name\":\"Charlie\",\"email\":\"charlie@example.com\"}"
# Accessing a Route That Does Not Exist
curl http://localhost:3000/unknown
[{"id":1,"name":"Bob","email":"bob@example.com"},{"id":2,"name":"Alice","email":"alice@example.com"}]
{"id":1,"name":"Bob","email":"bob@example.com"}
{"id":3,"name":"Charlie","email":"charlie@example.com"}
{"error":"Route not found"}
❓ Perguntas Frequentes
P: Qual é a diferença entre o módulo http e o Express? R: O http é um módulo embutido de baixo nível do Node.js que oferece apenas o gerenciamento mais básico de solicitações e respostas; o Express é uma estrutura construída sobre o módulo http que inclui recursos avançados, como roteamento, middleware e um mecanismo de modelos, proporcionando maior eficiência no desenvolvimento, mas introduzindo dependências adicionais.
P: Como faço para recuperar o corpo de uma solicitação POST? R: O objeto
reqé um fluxo legível. Você precisa aguardar o eventodatapara coletar os blocos do buffer e concatená-los; em seguida, aguardar o eventoendpara indicar que a recepção dos dados está concluída e, por fim, usarJSON.parse()ouBuffer.concat()para processar os dados completos.
P: Qual é a diferença entre res.end() e res.write()? R:
res.end()Envia dados e fecha a resposta; deve ser chamado uma vez — e apenas uma vez — para cada solicitação;res.write()apenas grava os dados, mas não fecha a resposta; pode ser chamado várias vezes para transmissão contínua ou em blocos, masres.end()ainda deve ser chamado no final para fechar a resposta.
P: Por que é necessário definir o Content-Type ao retornar JSON? R: Se o Content-Type não for definido, o padrão é
text/plain. Os clientes (navegadores, fetch, curl) não analisarão automaticamente a resposta como JSON, o que pode resultar em errosresponse.json()ou na exibição incorreta dos dados. Definir o parâmetro comoapplication/jsongarante que os clientes saibam como analisar o corpo da resposta.
P: Como faço para lidar com parâmetros de consulta em uma URL? R: Use
new URL(req.url, 'http://localhost')para criar um objeto URL; em seguida, useurl.searchParams.get('key')para recuperar os valores dos parâmetros ou useurl.searchParams.entries()para percorrer todos os parâmetros.
P: Qual é a finalidade do segundo callback para
server.listen? R: É um callback que é acionado após o servidor ter sido iniciado com sucesso e costuma ser usado para exibir logs de inicialização. Se você não passar um callback, também pode monitorar o eventoserver.on('listening', callback), que tem o mesmo efeito.
P: Por que o segundo parâmetro de
new URLprecisa incluirbase? R:req.urlcontém apenas a parte do caminho (por exemplo,/api?id=1) e não é uma URL completa.new URL()requer um parâmetrobasepara completar o protocolo e o nome do host; caso contrário, será gerado umTypeError. O valor debasenão afeta os resultados da análise depathnameesearchParams.
📖 Resumo
- Conceitos-chave e como aplicá-los
- Conceitos básicos e como usar o primeiro servidor HTTP
- Conceitos fundamentais e utilização do ciclo de vida da solicitação-resposta HTTP
- Conceitos-chave e uso das propriedades principais do objeto
request - Conceitos-chave e uso dos métodos principais do objeto
response - Conceitos básicos e uso do roteamento de URLs
- Conceitos básicos e uso de solicitações GET e parâmetros de consulta
- Conceitos básicos e uso de solicitações POST e coleta do corpo da solicitação
📝 Exercícios
- Conclua todos os exemplos de código desta lição e certifique-se de que cada um deles seja executado corretamente.
- Modifique o exemplo completo e adicione suas próprias extensões
- Analise a documentação oficial, identifique 1 ou 2 APIs que não foram abordadas nesta aula e escreva um código de teste para elas.
- Reflexão: Como você aplicaria o que aprendeu nesta aula a um projeto do mundo real?
- Tente combinar o que você aprendeu nesta aula com o conteúdo das aulas anteriores para criar um pequeno projeto.