Noções Básicas de HTTP em Node
10 exemplos para entender HTTP em Node.js com http.createServer - 7 básicos e 3 intermediários.
Busque em todas as páginas da documentação
10 exemplos para entender HTTP em Node.js com http.createServer - 7 básicos e 3 intermediários.
Estes exemplos assumem Node.js 24.18.0 (Active LTS) e TypeScript 5.6+ com ESM ("type": "module" em package.json).
mkdir http-basics-spike && cd http-basics-spike
npm init -y
npm pkg set type=module
npm install -D typescript@5.6 tsx @types/nodePara padrões em nível de framework construídos sobre esta base, veja Padrão de Middleware e Noções Básicas de Express.
Todo servidor HTTP do Node começa com http.createServer e um manipulador de requisições.
import { createServer } from "node:http";
const server = createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Olá do Node HTTP\n");
});
server.listen(3000, () => {
console.log("Ouvindo em http://localhost:3000");
});req é um IncomingMessage com method, url e headersres é um ServerResponse - você deve chamar res.end() ou o cliente esperará para semprewriteHead define o status e os cabeçalhos em uma única chamada; use-o antes do primeiro writeRelacionado: Roteamento Sem Frameworks - correspondência de caminhos sem Express
Roteie inspecionando req.method e analisando req.url.
import { createServer } from "node:http";
import { parse } from "node:url";
const server = createServer((req, res) => {
const { pathname } = parse(req.url ?? "/", true);
if (req.method === "GET" && pathname === "/health") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ status: "ok" }));
return;
}
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Não encontrado" }));
});req.url inclui a string de consulta - use URL ou parse de node:url para o nome do caminhoreq.path e req.queryOs cabeçalhos chegam em minúsculas no Node 24. Acesse-os via req.headers.
import { createServer } from "node:http";
const server = createServer((req, res) => {
const contentType = req.headers["content-type"] ?? "none";
const userAgent = req.headers["user-agent"] ?? "unknown";
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ contentType, userAgent }));
});, em um único valor de stringX-Forwarded-For sem configuração de proxy - veja Consciência de Proxy ReversoDefina Content-Type: application/json e serialize sua carga útil.
import { createServer } from "node:http";
const users = [{ id: 1, name: "Ada" }];
const server = createServer((req, res) => {
res.writeHead(200, {
"Content-Type": "application/json; charset=utf-8",
});
res.end(JSON.stringify({ data: users }));
});charset=utf-8 para JSON com texto não ASCIIJSON.stringify com um substituto para datas: date.toISOString()Colete os pedaços de data do stream da requisição e, em seguida, analise.
import { createServer } from "node:http";
async function readBody(req: import("node:http").IncomingMessage): Promise<string> {
const chunks: Buffer[] = [];
for await (const chunk of req) {
chunks.push(chunk as Buffer);
}
return Buffer.concat(chunks).toString("utf8");
}
const server = createServer(async (req, res) => {
if (req.method !== "POST") {
res.writeHead(405).end();
return;
}
try {
const body = JSON.parse(await readBody(req));
res.writeHead(201, { "Content-Type": "application/json" });
res.end(JSON.stringify({ received: body }));
} catch {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "JSON inválido" }));
}
});express.json() do Express e o analisador integrado do Fastify lidam com isso com limitesUse códigos de status significativos; clientes e balanceadores de carga dependem deles.
import { createServer } from "node:http";
const server = createServer((req, res) => {
if (req.method === "GET" && req.url === "/users/999") {
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Usuário não encontrado" }));
return;
}
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ id: 1, name: "Ada" }));
});| Código | Significado | Quando usar |
|---|---|---|
| 200 | OK | GET, PUT, PATCH bem-sucedidos |
| 201 | Created | POST bem-sucedido que criou um recurso |
| 400 | Bad Request | Falha de validação, entrada malformada |
| 404 | Not Found | Recurso não existe |
| 500 | Internal Error | Exceção não tratada (registre-a, não vaze detalhes) |
Feche o servidor no SIGTERM para que as requisições em andamento terminem.
import { createServer } from "node:http";
const server = createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("ok\n");
});
server.listen(3000);
function shutdown() {
console.log("Desligando...");
server.close(() => {
console.log("Servidor fechado");
process.exit(0);
});
setTimeout(() => process.exit(1), 10_000).unref();
}
process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);server.close() para de aceitar novas conexões, mas permite que as requisições ativas concluamSIGTERM antes de remover pods do serviçoEvite que clientes lentos mantenham conexões abertas indefinidamente.
import { createServer } from "node:http";
const server = createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("ok\n");
});
server.requestTimeout = 30_000; // 30s por requisição
server.headersTimeout = 35_000; // deve exceder requestTimeout
server.keepAliveTimeout = 5_000; // timeout ocioso do socket keep-alive
server.listen(3000);requestTimeout (Node 18+) destrói requisições que excedem o limiteheadersTimeout deve ser maior que requestTimeoutkeepAliveTimeout para corresponder ao seu proxy reverso - veja Keep-Alive e Limites de ConexãoTransmita arquivos grandes em vez de lê-los na memória.
import { createServer } from "node:http";
import { createReadStream } from "node:fs";
import { stat } from "node:fs/promises";
import { join } from "node:path";
const server = createServer(async (req, res) => {
const filePath = join(process.cwd(), "public", "report.pdf");
try {
const info = await stat(filePath);
res.writeHead(200, {
"Content-Type": "application/pdf",
"Content-Length": info.size,
});
createReadStream(filePath).pipe(res);
} catch {
res.writeHead(404).end();
}
});pipe lida com backpressure automaticamenteContent-Length quando conhecido para melhores indicadores de progresso do clienteerror no stream de leitura para evitar respostas pendentesnode:httpsEnvolva o mesmo padrão de manipulador em https.createServer com certificados TLS.
import { createServer as createHttpsServer } from "node:https";
import { readFileSync } from "node:fs";
const server = createHttpsServer(
{
key: readFileSync("certs/key.pem"),
cert: readFileSync("certs/cert.pem"),
},
(req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("HTTPS ok\n");
}
);
server.listen(3443);mkcert ou os certificados de desenvolvimento da sua plataformaRaramente para APIs de aplicativos. Use Express, Fastify ou NestJS para roteamento, análise e middleware. Conheça o módulo bruto para depuração, sidecars de verificação de integridade e para entender o que os frameworks abstraem.
Você provavelmente esqueceu res.end() ou o chamou duas vezes. Cada requisição precisa de exatamente uma resposta terminal. Verifique os caminhos de código que caem sem finalizar.
Sim para I/O, mas rejeições de promessa não tratadas em manipuladores http brutos não são capturadas automaticamente. Envolva em try/catch ou use um framework que lide com erros assíncronos (Express 5 faz isso).
writeHead envia status e cabeçalhos imediatamente. setHeader enfileira cabeçalhos até o primeiro write ou end. Misturá-los após o início das escritas lança ERR_HTTP_HEADERS_SENT.
Defina Access-Control-Allow-Origin e manipule o preflight OPTIONS manualmente, ou use um middleware de framework. Veja Middleware de Segurança.
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026