Documentações de API e as ferramentas de desenvolvedor do navegador costumam apresentar a requisição de exemplo como um comando cURL. É ideal para um teste rápido no terminal; mas quando você precisa levar a mesma requisição para uma aplicação Node.js ou para um script de coleta de dados, precisa converter o comando para JavaScript. Neste artigo explicamos os equivalentes em JavaScript das opções mais usadas do cURL, exemplos de conversão, quatro formas de usar proxy no Node.js, tratamento de erros e os erros mais comuns.
Todos os exemplos foram testados no Node.js 24, com undici 8 e Axios 1.20.
Qual é o equivalente do cURL em JavaScript?
Existem duas opções principais:
- fetch: vem embutido nos navegadores e, desde o Node.js 18, também no Node.js. Não exige pacote adicional. A implementação de fetch do Node.js usa a biblioteca undici por baixo dos panos.
- Axios: biblioteca popular, usada há muito tempo, que converte JSON automaticamente e oferece suporte a interceptadores de requisição e resposta.
Também é possível reutilizar um comando cURL sem sair do terminal (via child_process), mas esse método dificulta o tratamento de erros e a portabilidade; você fica dependente de o cURL estar instalado na máquina. Escrever com um cliente nativo é quase sempre melhor.
Equivalentes em JavaScript das opções do cURL
| cURL | fetch | Axios |
|---|---|---|
curl URL | fetch(url) | axios.get(url) |
-X POST | method: "POST" | axios.post(url, dados) |
-H "Nome: Valor" | headers: { Nome: "Valor" } | headers: { Nome: "Valor" } |
-d '{"a":1}' | body: JSON.stringify({ a: 1 }) | objeto como segundo parâmetro |
-d "a=1&b=2" | body: new URLSearchParams({ a: 1, b: 2 }) | new URLSearchParams(...) como segundo parâmetro |
-F "arquivo=@a.png" | body: FormData | FormData como segundo parâmetro |
-u usuario:senha | cabeçalho Authorization: "Basic ..." | auth: { username, password } |
-b "nome=valor" (cookie) | headers: { Cookie: "nome=valor" } | headers: { Cookie: "nome=valor" } |
-A "UA" | headers: { "User-Agent": "UA" } | headers: { "User-Agent": "UA" } |
-L (segue redirecionamento) | Segue por padrão | Segue por padrão |
-x proxy | dispatcher: new ProxyAgent(...) | httpsAgent ou proxy |
-m 20 (tempo limite) | signal: AbortSignal.timeout(20000) | timeout: 20000 |
-i (cabeçalhos de resposta) | response.headers | response.headers |
-o arquivo | escreva o corpo com fs.writeFile | responseType: "stream" |
Exemplo: convertendo uma requisição POST
Vamos considerar o seguinte comando cURL:
curl -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TOKEN" \
-d '{"q": 1}'Com fetch
const response = await fetch("https://httpbin.org/post", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer TOKEN",
},
body: JSON.stringify({ q: 1 }),
signal: AbortSignal.timeout(20000),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
console.log(data.json);O fetch tem uma particularidade: quando o servidor retorna 404 ou 500, ele não lança erro. Você mesmo precisa checar se a resposta foi bem-sucedida usando response.ok. Já um erro de rede (DNS, conexão recusada, tempo limite) chega como exceção.
Com Axios
npm install axiosimport axios from "axios";
const { data } = await axios.post(
"https://httpbin.org/post",
{ q: 1 },
{ headers: { Authorization: "Bearer TOKEN" }, timeout: 20000 },
);
console.log(data.json);O Axios converte o objeto para JSON automaticamente, adiciona o cabeçalho Content-Type e lança erro em respostas fora da faixa 2xx.
Exemplo: envio de formulário e upload de arquivo
Um envio de formulário no formato -d "a=1&b=2" do cURL é atendido em JavaScript com URLSearchParams:
const response = await fetch("https://httpbin.org/post", {
method: "POST",
body: new URLSearchParams({ a: "1", b: "2" }),
});
console.log((await response.json()).form);Quando um corpo URLSearchParams é passado, o fetch define sozinho o cabeçalho Content-Type como application/x-www-form-urlencoded. Para upload de arquivo (-F), usa-se FormData, e o valor de fronteira (boundary) também é adicionado automaticamente. Um detalhe: se você importa a função fetch do pacote undici, importe também a classe FormData do mesmo pacote; o FormData embutido não combina com o fetch do undici, e o corpo vai como texto puro.
import { openAsBlob } from "node:fs";
const form = new FormData();
form.append("arquivo", await openAsBlob("./a.png"), "a.png");
const response = await fetch("https://httpbin.org/post", { method: "POST", body: form });
console.log(Object.keys((await response.json()).files));Quatro formas de usar proxy no Node.js
No cURL, o proxy é uma única opção, -x. No Node.js, o método muda de acordo com o cliente que você usa.
1. fetch e o ProxyAgent do undici
npm install undiciimport { fetch, ProxyAgent } from "undici";
const dispatcher = new ProxyAgent("http://kullanici:parola@pr.proxynet.io:8000");
const response = await fetch("https://httpbin.org/ip", { dispatcher });
console.log(await response.text());Note que também importamos a função fetch do pacote undici. O fetch embutido do Node.js também é baseado no undici, mas, como pode haver diferença de versão no pacote instalado separadamente, importar os dois do mesmo pacote é o caminho mais seguro.
2. Configuração global para todas as chamadas fetch
Se você quer que toda chamada fetch da aplicação use o mesmo proxy, pode definir um dispatcher global:
import { ProxyAgent, setGlobalDispatcher } from "undici";
setGlobalDispatcher(new ProxyAgent("http://kullanici:parola@pr.proxynet.io:8000"));
const response = await fetch("https://httpbin.org/ip");
console.log(await response.text());Esse método também cobre chamadas fetch feitas dentro de uma biblioteca de terceiros; você passa o tráfego dela pelo proxy sem tocar no código-fonte da biblioteca.
3. Por variável de ambiente, sem alterar código
Versões recentes do Node.js conseguem ler as variáveis de ambiente padrão de proxy para o fetch embutido quando a variável NODE_USE_ENV_PROXY está ativada:
NODE_USE_ENV_PROXY=1 HTTPS_PROXY="http://kullanici:parola@pr.proxynet.io:8000" node aplicacao.mjsEsse método é útil para passar um script já existente pelo proxy sem tocar no código-fonte. A variável NO_PROXY também é lida; você pode adicionar endereços de rede interna a essa lista para mantê-los fora do proxy. Verifique na documentação do Node.js se esse recurso está disponível na sua versão.
4. Axios e destinos HTTPS
A opção proxy embutida do Axios funciona sem problemas para endereços HTTP sem criptografia:
const { data } = await axios.get("http://httpbin.org/ip", {
proxy: {
protocol: "http",
host: "pr.proxynet.io",
port: 8000,
auth: { username: "kullanici", password: "parola" },
},
});Para endereços HTTPS, é mais confiável usar um agente de proxy:
npm install https-proxy-agentimport axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const httpsAgent = new HttpsProxyAgent("http://kullanici:parola@pr.proxynet.io:8000");
const { data } = await axios.get("https://httpbin.org/ip", { httpsAgent, proxy: false });
console.log(data);A linha proxy: false é importante; ela desliga a própria lógica de proxy do Axios e deixa o túnel totalmente a cargo do agente. Se você criar o agente uma vez e vinculá-lo a uma instância com axios.create({ httpsAgent, proxy: false }), não precisa reescrevê-lo em cada chamada.
Comparando os quatro métodos
| Método | Escopo | Alteração de código | Situação em que é indicado |
|---|---|---|---|
ProxyAgent do undici | Uma única chamada | dispatcher em cada chamada | Proxy diferente para requisições diferentes |
setGlobalDispatcher | Todas as chamadas fetch | Uma linha, no início | Um único proxy para toda a aplicação |
NODE_USE_ENV_PROXY | Todas as chamadas do fetch embutido | Nenhuma | Script existente, ambiente de implantação |
| Axios + agente | Instância do Axios | httpsAgent + proxy: false | Quando o projeto já usa Axios |
Nova tentativa e concorrência
Em um script real de coleta de dados, as requisições às vezes falham; o proxy pode não alcançar o destino, ou o site pode retornar 429. A função auxiliar abaixo tenta novamente a requisição com falha usando espera exponencial e limita o número de requisições abertas ao mesmo tempo:
import { fetch, ProxyAgent } from "undici";
const dispatcher = new ProxyAgent("http://kullanici:parola@pr.proxynet.io:8000");
async function getir(url, deneme = 3) {
for (let i = 0; i < deneme; i++) {
try {
const r = await fetch(url, { dispatcher, signal: AbortSignal.timeout(20000) });
if (r.status === 429 || r.status >= 500) throw new Error(`HTTP ${r.status}`);
return await r.text();
} catch (hata) {
if (i === deneme - 1) throw hata;
await new Promise((coz) => setTimeout(coz, 1000 * 2 ** i));
}
}
}
async function topluGetir(urls, esZamanli = 5) {
const sonuclar = [];
for (let i = 0; i < urls.length; i += esZamanli) {
const grup = urls.slice(i, i + esZamanli);
sonuclar.push(...(await Promise.allSettled(grup.map(getir))));
}
return sonuclar;
}
const urls = Array.from({ length: 20 }, (_, i) => `https://httpbin.org/get?i=${i}`);
const sonuclar = await topluGetir(urls);
console.log(sonuclar.filter((s) => s.status === "fulfilled").length, "com sucesso");O Promise.allSettled evita que o erro de uma requisição derrube todo o grupo; você pode examinar cada resultado individualmente. O tempo de espera dobra a cada tentativa; insistir em intervalos fixos pode fazer um site com limite de taxa aplicar restrições ainda mais rígidas.
Erros comuns
Caractere especial na senha
Se a sua senha de proxy tiver caracteres como @, : ou /, codifique-os dentro do endereço com encodeURIComponent. Caso contrário, o endereço é interpretado errado e você recebe o erro "407 Proxy Authentication Required".
Requisições sem tempo limite
Nas configurações padrão, uma requisição pode esperar resposta por muito tempo e travar o seu script. Coloque um limite de tempo em cada requisição com AbortSignal.timeout no fetch e timeout no Axios.
Muitas requisições ao mesmo tempo
Disparar centenas de requisições de uma vez com Promise.all sobrecarrega tanto os seus próprios limites de conexão quanto faz você esbarrar em limite de taxa no site de destino. Limite a concorrência em pequenos grupos, como no exemplo acima. Em trabalhos com muitas requisições, o Proxies rotativos distribui o tráfego entre IPs diferentes e reduz o risco de bloqueio.
Passar agent para o fetch embutido
Na antiga API http.request do Node.js, o proxy é passado pela opção agent. O fetch embutido não reconhece essa opção e a ignora silenciosamente; a requisição sai sem proxy. Para o fetch, a chave correta é dispatcher.
Copiar cabeçalhos do navegador tal como estão
Requisições copiadas das ferramentas de desenvolvedor carregam cabeçalhos específicos do navegador, como sec-ch-ua e sec-fetch-*. No Node.js não é necessário enviá-los, e alguns podem ser avaliados como uma inconsistência pelo site de destino; deixe apenas os cabeçalhos realmente necessários.
Páginas em que a requisição HTTP não basta
O fetch e o Axios só obtêm o HTML retornado pelo servidor. Se o conteúdo é carregado depois, no navegador, com JavaScript, você não vai encontrar o que procura na página. Nesse caso, você precisa encontrar a requisição de API que roda em segundo plano ou usar uma automação de navegador. Comparamos as opções no artigo Extração de dados: JavaScript ou Python?; mostramos o uso de proxy com o Puppeteer no artigo Puppeteer e CAPTCHA.
fetch ou Axios?
- Escolha fetch se você não quer uma dependência adicional, se o código vai rodar tanto no navegador quanto no Node.js, ou se quer aproveitar os recursos de gerenciamento de conexão do undici.
- Escolha Axios se você precisa de conveniências como conversão automática de JSON, interceptadores e erro automático em respostas fora do 2xx, ou se o projeto já o usa.
A diferença entre os dois está mais no hábito do que na função. Começar um projeto novo com fetch mantém o número de dependências baixo; em um projeto grande já feito com Axios, não há motivo para migrar para o fetch.
Perguntas frequentes
Posso converter um comando cURL para JavaScript automaticamente?
Nas ferramentas de desenvolvedor do navegador, na aba Rede, você pode clicar com o botão direito em uma requisição e usar a opção "Copy as fetch" para copiar diretamente como código fetch. Ainda assim, revise o código gerado; cabeçalhos específicos do navegador podem ser desnecessários no Node.js.
Posso usar proxy SOCKS5 no Node.js?
O fetch embutido e o ProxyAgent do undici são para proxy HTTP. Para SOCKS5, você precisa definir um agente com um pacote adicional, como socks-proxy-agent. No lado do cURL, o esquema socks5h:// já é suportado diretamente; os detalhes estão no artigo Como usar proxy com o cURL?.
Dá para definir proxy em JavaScript rodando no navegador?
Não. O fetch do navegador não permite alterar a configuração de proxy por código; o proxy é definido nas configurações do navegador ou do sistema operacional. Gerenciar o proxy a partir do código é algo específico de ambientes de servidor, como o Node.js. Para proxy no nível do navegador, são usadas extensões como o SwitchyOmega.
Como mantenho cookies entre requisições?
O fetch embutido não guarda cookies. Você precisa ler o cabeçalho Set-Cookie da resposta e adicioná-lo como cabeçalho Cookie na requisição seguinte; ou pode usar um cookie jar baseado em tough-cookie com o Axios. Não esqueça que, em fluxos com login, o IP também precisa se manter fixo; o Proxies de sessão fixa foi feito para isso.
Posso usar um proxy diferente em cada requisição?
Sim. Com o undici, você pode passar um ProxyAgent diferente em cada chamada. Mas, em vez de gerenciar a lista você mesmo, usar um proxy rotativo é mais simples: um único endereço, um IP de saída diferente em cada conexão.
O mesmo código funciona em TypeScript?
Sim. O undici e o Axios vêm com definições de tipo; para a opção dispatcher, é preciso usar o próprio tipo fetch do undici, porque a definição de tipo do fetch embutido não conhece essa opção.
Em resumo
Comandos cURL podem ser atendidos em JavaScript, ponto a ponto, com fetch ou Axios. No Node.js, existem quatro caminhos para proxy: o ProxyAgent do undici, o dispatcher global, a variável de ambiente NODE_USE_ENV_PROXY e o agente de proxy do Axios. Adicionar desde o início o tempo limite, o tratamento de erro, a nova tentativa com espera exponencial e o limite de concorrência torna os seus scripts muito mais confiáveis. Você encontra os pacotes adequados para tráfego web na nossa página de Proxies HTTPS.




