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

FormData no Node.js: Guia Prático

Atualizado em: 14 de agosto de 2026

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

O FormData no Node.js permite montar corpos multipart/form-data para enviar campos de texto, arquivos, imagens e outros blobs por HTTP. A API segue o padrão da Web e integra diretamente com o fetch nativo, tornando uploads mais consistentes entre navegador e backend.

Apesar da interface simples, uploads exigem limites, validação de tipo, nomes seguros, timeouts e proteção contra SSRF. Também é importante não definir manualmente o boundary do Content-Type, porque ele precisa corresponder ao corpo serializado.

Neste guia, você aprenderá a criar formulários, adicionar campos, anexar Blob e File, enviar com fetch, receber respostas, trabalhar com arquivos do filesystem, controlar memória, testar e evitar vulnerabilidades.

O que é FormData?

FormData representa um conjunto de pares entre nomes e valores, serializado como multipart. A documentação oficial de FormData no Node.js mostra a API global. A documentação de FormData na MDN explica os métodos padronizados.

Para requisições, consulte Fetch Nativo no Node.js. Para dados binários, veja Buffer no Node.js. O artigo Web Streams API no Node.js ajuda a entender corpos em fluxo.

Criando um formulário

const form = new FormData();
form.set('name', 'Ana');
form.set('active', 'true');

Valores simples são convertidos para texto. Números e booleanos devem ser serializados de forma explícita para evitar ambiguidades.

append() e set()

form.append('tag', 'node');
form.append('tag', 'javascript');
form.set('category', 'backend');

append() adiciona outro valor à mesma chave. set() substitui os valores anteriores.

Lendo valores

console.log(form.get('name'));
console.log(form.getAll('tag'));
console.log(form.has('category'));

Use getAll() quando a chave pode aparecer várias vezes.

Removendo um campo

form.delete('temporary');

Esse método remove todos os valores associados à chave.

Iterando

for (const [name, value] of form.entries()) {
  console.log(name, value);
}

Não registre blobs, tokens ou dados pessoais sem sanitização.

Enviando com fetch

const response = await fetch('https://api.example.com/profile', {
  method: 'POST',
  body: form
});

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

Quando o body é FormData, o fetch define o Content-Type com boundary.

Não defina o boundary manualmente

const response = await fetch(url, {
  method: 'POST',
  headers: {
    'content-type': 'multipart/form-data'
  },
  body: form
});

Esse exemplo está incorreto porque o header não inclui o boundary gerado. Remova o Content-Type e deixe a implementação criá-lo.

Adicionando Blob

const content = new Blob(
  ['conteúdo do arquivo'],
  { type: 'text/plain' }
);

form.set('document', content, 'document.txt');

O terceiro argumento define o nome enviado ao servidor.

Adicionando File

const file = new File(
  [bytes],
  'photo.jpg',
  { type: 'image/jpeg' }
);

form.set('photo', file);

A disponibilidade de File depende da versão do Node.js. Consulte a documentação do runtime usado.

Arquivo do filesystem

const fs = require('node:fs/promises');

const bytes = await fs.readFile('./uploads/report.pdf');
const blob = new Blob([bytes], {
  type: 'application/pdf'
});

form.set('report', blob, 'report.pdf');

readFile() carrega todo o arquivo em memória. Para arquivos grandes, use uma estratégia compatível com streaming ou biblioteca que suporte upload incremental.

Veja File System no Node.js para caminhos e permissões.

Tipos MIME

O tipo informado pelo cliente é apenas uma indicação. O servidor deve validar conteúdo, extensão, tamanho e assinatura de arquivo.

Nomes de arquivo

Nunca use diretamente o nome recebido para criar um caminho local:

const unsafePath = path.join(uploadRoot, uploadedName);

Gere um identificador próprio e mantenha o nome original apenas como metadado sanitizado.

Campos JSON

form.set('metadata', JSON.stringify({
  title: 'Relatório',
  category: 'finance'
}));

O servidor precisa analisar e validar esse JSON separadamente.

Arrays

for (const tag of tags) {
  form.append('tags', tag);
}

Documente se o servidor espera chaves repetidas, colchetes ou JSON.

Booleanos e números

form.set('active', String(active));
form.set('page', String(page));

Na recepção, faça conversão explícita e valide faixas.

Timeout

const response = await fetch(url, {
  method: 'POST',
  body: form,
  signal: AbortSignal.timeout(15000)
});

Uploads grandes podem exigir prazo maior, mas um timeout ilimitado permite conexões penduradas.

Cancelamento do usuário

const controller = new AbortController();

const promise = fetch(url, {
  method: 'POST',
  body: form,
  signal: controller.signal
});

controller.abort();

Cancelar localmente não garante que o servidor não recebeu parte ou todo o arquivo.

Autenticação

const response = await fetch(url, {
  method: 'POST',
  headers: {
    authorization: `Bearer ${token}`
  },
  body: form
});

Não inclua o token em campos do formulário ou logs.

Resposta JSON

if (!response.ok) {
  const message = await response.text();
  throw new Error(`Upload falhou: ${response.status}`);
}

const result = await response.json();

Limite o corpo de erro e não exponha a resposta completa ao usuário.

Memória

Construir um Blob a partir de um Buffer grande pode duplicar referências ou cópias, dependendo da operação. Meça RSS e heap durante uploads reais.

Uploads concorrentes

Limite quantos arquivos são preparados e enviados simultaneamente. Dez uploads de 500 MB podem esgotar memória e largura de banda.

const limit = createConcurrencyLimit(3);

await Promise.all(files.map(file =>
  limit(() => uploadFile(file))
));

Retry

Não repita uploads automaticamente sem entender se o servidor criou o recurso. Use chaves de idempotência ou protocolo de upload resumível.

Consulte Retry com Backoff no Node.js.

Upload resumível

Para arquivos grandes e redes instáveis, prefira protocolos com partes, offset e confirmação. FormData comum envia o corpo inteiro novamente após falha.

Segurança no destino

Se a URL é fornecida pelo usuário, há risco de SSRF. Use allowlist de hosts, bloqueie redes privadas, controle redirects e limite portas.

Recebendo multipart

FormData é uma API para construir e manipular o formulário. Para receber multipart em um servidor Node.js, use um parser confiável com limites de:

  • tamanho total;
  • tamanho por arquivo;
  • quantidade de campos;
  • quantidade de arquivos;
  • comprimento de nomes;
  • tempo de upload.

Arquivos temporários

Parsers podem gravar em disco temporário. Configure diretório, permissões, quotas e remoção após erro.

Validação de imagem

Não confie apenas no Content-Type. Analise dimensões, assinatura e formato real. Reencode imagens quando necessário para remover conteúdo inesperado.

Antivírus

Ambientes com documentos enviados por terceiros podem exigir varredura antes de disponibilizar o arquivo.

Observabilidade

Registre:

  • destino sanitizado;
  • quantidade de campos;
  • tamanho total;
  • duração;
  • status;
  • cancelamento;
  • tentativa;
  • identificador da operação.

Não registre conteúdo, nomes sensíveis ou tokens.

Testes

Cubra:

  • campo simples;
  • chaves repetidas;
  • arquivo vazio;
  • arquivo grande;
  • Unicode no nome;
  • tipo MIME inválido;
  • timeout;
  • cancelamento;
  • resposta de erro;
  • limite de concorrência.

Use o Node Test Runner com um servidor local.

Erros comuns

  • Definir Content-Type manualmente: boundary fica incorreto.
  • Ler arquivo gigante inteiro: memória cresce.
  • Confiar no MIME: conteúdo malicioso passa.
  • Usar nome original como caminho: ocorre path traversal.
  • Retry sem idempotência: uploads duplicam.
  • Sem timeout: conexão fica aberta.
  • Concorrência ilimitada: recursos são esgotados.

Boas práticas

  • Deixe o fetch gerar o boundary.
  • Valide campos e arquivos.
  • Limite tamanho e quantidade.
  • Gere nomes internos.
  • Use timeout e cancelamento.
  • Controle concorrência.
  • Evite carregar arquivos grandes em memória.
  • Proteja URLs contra SSRF.
  • Use idempotência.
  • Remova temporários.

Conclusão

O FormData no Node.js simplifica o envio de campos e arquivos com fetch usando uma API compatível com a Web.

Uploads seguros dependem de mais do que serialização. Limites, validação, nomes controlados, timeouts, idempotência e observabilidade evitam que uma operação conveniente se torne fonte de consumo excessivo, duplicidade ou vulnerabilidades. Com essas práticas, FormData funciona bem em integrações e serviços modernos.

Os 10 Melhores Cursos de Programação de 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