Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Fetch no Node.js

Atualizado em: 2 de outubro de 2026

Terminal Linux usado em desenvolvimento e administração de aplicações Node.js

O Node.js oferece uma implementação compatível com a API Fetch dos navegadores. Com fetch(), Request, Response, Headers, FormData e Web Streams, aplicações backend podem realizar chamadas HTTP usando um padrão conhecido.

A API é simples, mas produção exige mais que chamar uma URL. É preciso definir timeout, validar status, limitar corpo, proteger redirects, reutilizar conexões, classificar erros e aplicar retries somente quando seguros.

Primeira requisição

const response = await fetch('https://api.example.com/users/42');

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const user = await response.json();
console.log(user);

Fetch rejeita em falhas de rede, mas não rejeita automaticamente em status 404 ou 500. Sempre verifique response.ok ou response.status.

Headers

const response = await fetch(url, {
  headers: {
    accept: 'application/json',
    'user-agent': 'my-service/1.0',
  },
});

Não registre Authorization, Cookie ou tokens. Use um cliente por dependência para centralizar headers seguros.

POST com JSON

const response = await fetch('https://api.example.com/orders', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    accept: 'application/json',
  },
  body: JSON.stringify({ productId: 42, quantity: 2 }),
});

Para operações de criação, use idempotency key quando o serviço suportar. Uma falha de rede pode acontecer depois que o servidor processou a requisição.

Timeout

const response = await fetch(url, {
  signal: AbortSignal.timeout(5_000),
});

O timeout deve caber no deadline total. Se uma requisição de usuário tem oito segundos, não configure cada dependência com oito segundos em sequência.

Combinando cancelamento

const signal = AbortSignal.any([
  requestSignal,
  AbortSignal.timeout(3_000),
]);

const response = await fetch(url, { signal });

Assim, a chamada termina quando o cliente desconecta ou o prazo local expira.

Consumindo o corpo

O corpo só pode ser consumido uma vez:

const text = await response.text();

Depois disso, chamar json() falha. Escolha o formato com base no Content-Type e no contrato.

Limite de tamanho

response.json() pode acumular um corpo enorme. Para fontes não confiáveis, leia a stream e imponha limite:

async function readLimited(response, maxBytes) {
  if (!response.body) return Buffer.alloc(0);

  const reader = response.body.getReader();
  const chunks = [];
  let total = 0;

  while (true) {
    const { value, done } = await reader.read();
    if (done) break;

    total += value.byteLength;
    if (total > maxBytes) {
      await reader.cancel('Resposta excedeu o limite');
      throw new Error('Resposta grande demais');
    }
    chunks.push(value);
  }

  return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)));
}

Streaming

const response = await fetch(url);
if (!response.ok || !response.body) throw new Error('Falha');

for await (const chunk of response.body) {
  await processChunk(chunk);
}

Use streaming para arquivos, NDJSON e respostas grandes. Respeite backpressure e cancelamento.

Convertendo para Node Stream

import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import { createWriteStream } from 'node:fs';

await pipeline(
  Readable.fromWeb(response.body),
  createWriteStream('download.bin'),
);

FormData

const form = new FormData();
form.set('title', 'Documento');
form.set('file', new Blob([buffer]), 'document.bin');

const response = await fetch(url, {
  method: 'POST',
  body: form,
});

Não defina manualmente o boundary do Content-Type. Para arquivos grandes, confirme estratégia de streaming e limite memória.

URLSearchParams

const body = new URLSearchParams({
  grant_type: 'client_credentials',
  scope: 'read',
});

const response = await fetch(tokenUrl, {
  method: 'POST',
  headers: {
    'content-type': 'application/x-www-form-urlencoded',
  },
  body,
});

Redirects

Fetch pode seguir redirects. Em chamadas sensíveis, use controle:

const response = await fetch(url, {
  redirect: 'manual',
});

Um redirect pode levar a outro host e vazar credenciais ou atingir rede interna. Revalide cada destino.

SSRF

Nunca busque URL arbitrária sem proteção. Use allowlist, valide protocolo, porta, hostname, IP resolvido e redirects. Bloqueie metadados de cloud e redes privadas quando o recurso for externo.

Autenticação

const response = await fetch(url, {
  headers: {
    authorization: `Bearer ${token}`,
  },
});

Armazene tokens em secret manager, não em código. Evite propagar Authorization para redirect em outra origem.

Basic Auth

const credentials = Buffer
  .from(`${username}:${password}`)
  .toString('base64');

const response = await fetch(url, {
  headers: {
    authorization: `Basic ${credentials}`,
  },
});

Basic Auth exige HTTPS e proteção dos segredos.

Cookies

Fetch no backend não possui automaticamente o mesmo cookie jar de um navegador. Se precisar manter sessão, use uma biblioteca de cookie jar ou prefira autenticação por token.

Dispatcher

É possível usar um dispatcher do Undici para controlar pools:

const response = await fetch(url, {
  dispatcher: apiPool,
  signal,
});

Reutilize o dispatcher e feche-o no shutdown.

Retry

Retry deve considerar:

  • método idempotente;
  • status transitório;
  • erro de conexão;
  • Retry-After;
  • deadline restante;
  • backoff com jitter;
  • limite de tentativas.

Não repita qualquer POST automaticamente.

Função de cliente

async function fetchJson(url, {
  signal,
  method = 'GET',
  headers,
  body,
} = {}) {
  const combinedSignal = signal
    ? AbortSignal.any([signal, AbortSignal.timeout(5_000)])
    : AbortSignal.timeout(5_000);

  const response = await fetch(url, {
    method,
    headers,
    body,
    signal: combinedSignal,
    redirect: 'manual',
  });

  if (!response.ok) {
    const errorText = (await response.text()).slice(0, 1000);
    throw new Error(`HTTP ${response.status}: ${errorText}`);
  }

  return response.json();
}

Em produção, classifique erros e valide Content-Type.

Request e Response

const request = new Request(url, {
  method: 'GET',
  headers: { accept: 'application/json' },
});

const response = await fetch(request);

Essas classes ajudam em frameworks baseados em padrões web e testes.

Clone

response.clone() permite consumir duas ramificações, mas pode aumentar buffer se uma for lenta. Não use indiscriminadamente em corpos grandes.

Cache

O Fetch do Node.js não deve ser tratado como cache HTTP completo de navegador. Implemente cache na camada adequada ou use CDN, proxy e bibliotecas específicas.

Observabilidade

Meça DNS, conexão, TLS, tempo até headers, duração total, bytes, status, retries, redirects e aborts. Normalize a rota e a dependência para evitar alta cardinalidade.

Logs

Registre método, host conhecido, operação, status e duração. Não registre URL com query sensível, Authorization, Cookie ou corpo completo.

Testes

Use MockAgent do Undici ou servidor local. Teste 200, 404, 500, timeout, corpo inválido, resposta grande, redirect, cancelamento e conexão interrompida.

Erros comuns

  • não verificar response.ok;
  • não definir timeout;
  • usar json em corpo ilimitado;
  • seguir redirect arbitrário;
  • repetir POST sem idempotência;
  • não consumir resposta;
  • registrar tokens;
  • não propagar cancelamento;
  • criar dispatcher por chamada;
  • confundir cache do navegador com backend.

Fluxo recomendado

Centralize chamadas por dependência, defina deadline, valide status e Content-Type, limite corpos e proteja redirects. Use Undici no Node.js para controle de pools, AbortController para cancelamento, Circuit Breaker para falhas e DNS no Node.js para resolução.

Consulte a documentação oficial de Fetch no Node.js e a referência da Fetch API.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita