Geonode logo
Geonode Team

Geonode Team

Atualizado: 7 de outubro de 2026

Publicado: 2 de setembro de 2026

Como utilizar um proxy com o SuperAgent no Node.js

O SuperAgent não possui uma opção de proxy integrada. É necessário adicionar uma extensão ou definir um agente HTTP, e ambas as abordagens são complicadas por um conflito de nomes: o «`.agent()`» do SuperAgent já significa algo completamente diferente. Esse conflito gera uma confusão específica, em que as pessoas pensam que configuraram um proxy, quando na verdade configuraram um «cookie jar». Este guia aborda ambas as opções, a terminologia e a verificação que indica qual delas está efetivamente ativa.

Somos a Geonode e comercializamos proxies; por isso, este é um guia sobre como utilizar o nosso tipo de produto com um cliente específico. A frase que vale a pena ler, mesmo que ignore o resto: verifique o endereço de saída após a configuração, porque uma configuração de proxy que não funciona não produz qualquer erro. O SuperAgent enviará alegremente o seu pedido diretamente, devolverá um código 200 e não lhe dará qualquer indicação de que o proxy foi contornado. A secção de verificação tem quatro linhas e é a diferença entre saber e supor.

Note também que o SuperAgent funciona também em navegadores, onde nada disto se aplica — não é possível instruir um navegador a utilizar um proxy a partir de JavaScript, pelo que tudo aqui se aplica apenas ao Node.

O Problema da Terminologia

É importante esclarecer isto primeiro, porque dá origem a erros reais.

No SuperAgent, o comando .agent() sem argumentos cria uma cópia do SuperAgent que guarda os cookies. A documentação é explícita: «No Node, o SuperAgent não guarda cookies por predefinição, mas pode utilizar o método .agent() para criar uma cópia do SuperAgent que guarde cookies. Cada cópia tem um conjunto de cookies separado.»

const agent = request.agent();
await agent.post("/login").send({ user, pass });
await agent.get("/cookied-page");   // session cookie carried over

Esse agente também tem predefinições: «Os métodos de pedido normais chamados no agente serão utilizados como predefinições para todos os pedidos feitos por esse agente.»

Por outro lado, .agent(httpAgent) com um argumento define o http.Agent do Node para a solicitação, que é onde reside o suporte a proxy.

O mesmo nome de método, duas funções distintas, diferenciadas apenas pelo facto de se passar ou não um argumento. Se tiver lido sobre os agentes SuperAgent e sobre os agentes proxy na mesma sessão, vale a pena esclarecer isto antes de escrever qualquer código.

Opção 1: Um agente proxy

Esta é a abordagem a preferir, e a razão prende-se com a manutenção.

import request from "superagent";
import { HttpsProxyAgent } from "https-proxy-agent";

const agent = new HttpsProxyAgent("http://myuser:mypass@proxy.example.com:9000");

const res = await request
  .get("https://api.example.com/items")
  .agent(agent);

Para SOCKS, substitua o pacote:

import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://proxy.example.com:1080");

Note que é socks5h

em vez de socks5

. A variante h

resolve nomes de host no proxy em vez de localmente, o que impede que as consultas DNS sejam encaminhadas para o seu próprio resolvedor enquanto o tráfego sai por outro lado — uma fuga que anula silenciosamente o objetivo de utilizar um proxy para geolocalização.

E o proxy-agent

lida com qualquer protocolo que a URL especifique, o que é útil quando o proxy provém de uma configuração:

import { ProxyAgent } from "proxy-agent";
const agent = new ProxyAgent();   // reads http_proxy / https_proxy / no_proxy

Porquê estes pacotes em vez da extensão SuperAgent: todos os três são mantidos ativamente. Verificado no registo npm em setembro de 2026, proxy-agent

está na versão 8.0.2, https-proxy-agent

na 9.1.0 e socks-proxy-agent

na 10.1.0, todas publicadas em junho de 2026.

Rota Dois: superagent-proxy

A extensão criada especificamente para este fim e a ressalva que a acompanha.

import request from "superagent";
import superagentProxy from "superagent-proxy";

superagentProxy(request);

const res = await request
  .get("https://api.example.com/items")
  .proxy("http://myuser:mypass@proxy.example.com:9000");

O seu ficheiro README descreve-a como uma extensão da «classe Request do superagent com uma função .proxy(uri)» e refere que «é suportada pelo módulo proxy-agent».

A API é mais prática do que passar um agente. A chamada .proxy(uri) fica mais legível numa cadeia de chamadas e aceita URIs «HTTP, HTTPS ou SOCKS», delegando a seleção do protocolo a proxy-agent.

A ressalva é a data de lançamento. superagent-proxy está na versão 3.0.0, publicada em setembro de 2021 — com cerca de cinco anos à data da redação deste artigo, enquanto a sua dependência subjacente proxy-agent continuou a ser atualizada. Não está obsoleta nem está avariada, mas é um invólucro fino que não evoluiu, ao passo que o que envolve sim.

A consequência prática: se já o utiliza e funciona, não há urgência. Para código novo, utilizar um agente proxy diretamente implica apenas uma linha adicional e remove uma camada obsoleta da sua árvore de dependências — e, uma vez que a extensão é um invólucro em torno precisamente desse agente, não perde nada além da sintaxe.

Verificar se funcionou mesmo

As quatro linhas mais importantes.

const res = await request
  .get("https://api.ipify.org?format=json")
  .agent(agent);

console.log(res.body);

Execute-o com o agente e sem ele. Se o endereço não mudar, o proxy não está no caminho. O SuperAgent não apresenta nenhum erro, nenhum aviso nem nenhuma solicitação falhada quando isto acontece — o tráfego simplesmente segue diretamente.

Três razões pelas quais uma configuração normalmente não tem efeito:

Chamou .agent() sem nenhum argumento, criando uma cópia do SuperAgent com persistência de cookies em vez de definir um agente HTTP. Esta é uma armadilha terminológica e produz exatamente este sintoma.

Aplicou o agente à solicitação errada. O encadeamento do SuperAgent é por solicitação, pelo que um agente definido numa chamada não se aplica à seguinte. Para um comportamento consistente, coloque a criação da solicitação numa função.

O tipo de agente não corresponde ao destino. Um «HttpsProxyAgent» lida com destinos HTTPS; um destino HTTP simples pode necessitar da variante HTTP. O «proxy-agent» contorna isto, escolhendo por si.

Para proxies com segmentação geográfica, a verificação do endereço não é suficiente. Verifique pelo resultado — solicite algo que diferencie genuinamente consoante a região e confirme se a resposta mudou. Um serviço de pesquisa que indique o país correto, enquanto a sua API devolve dados da sua região de origem, significa que a segmentação não está a atingir o destino pretendido, o que corresponde ao padrão de falha silenciosa que descrevemos em por que razão é importante testar proxies.

Tempos limite através de um proxy

O modelo de tempo limite do SuperAgent é excepcionalmente bom e vale a pena utilizá-lo corretamente quando um proxy aumenta a latência.

A documentação descreve duas configurações. req.timeout({deadline: ms})

— ou req.timeout(ms)

— «define um prazo para que toda a solicitação (incluindo todos os uploads, redirecionamentos e tempo de processamento do servidor) seja concluída. Se a resposta não for totalmente descarregada dentro desse prazo, a solicitação será abortada.» E req.timeout({response: ms})

«define o tempo máximo de espera pela chegada do primeiro byte do servidor, mas não limita a duração total do descarregamento.»

O próprio conselho da documentação sobre o dimensionamento é diretamente relevante para pedidos encaminhados por proxy: «O tempo limite de resposta deve ser, pelo menos, alguns segundos mais longo do que apenas o tempo que o servidor demora a responder, porque também inclui o tempo para efetuar a pesquisa de DNS, as ligações TCP/IP e TLS, e o tempo para enviar os dados do pedido.»

Através de um proxy, cada uma dessas fases tem um custo adicional. Uma saída residencial acrescenta latência real por pedido, e isso deve-se à distância e não a uma falha.

const res = await request
  .get("https://api.example.com/items")
  .agent(agent)
  .timeout({ response: 15000, deadline: 60000 });

A documentação recomenda a utilização de ambos, e a razão é a mesma que em qualquer outro contexto: um tempo limite de resposta deteta um servidor que nunca responde, enquanto um prazo deteta um que responde e depois demora a enviar os dados. Nenhuma delas, por si só, abrange ambos os casos.

Defina os valores com base nas medições efetuadas através do proxy, em vez de o fazer por hábito, ou irá gerar falhas que parecem ser causadas por um proxy avariado, mas que são simplesmente latência que não teve em conta.

Tratamento de erros

O comportamento predefinido do SuperAgent difere do da maioria dos clientes e isso é importante neste contexto.

A documentação é enfática: «O SuperAgent considera as respostas 4xx e 5xx (bem como as respostas 3xx não tratadas) como erros por predefinição». Acrescenta ainda que «esta informação de estado estará disponível através de err.status», e que tais erros «também contêm um campo err.response».

Assim, uma falha na autenticação do proxy surge como uma rejeição, em vez de uma resposta:

try {
  const res = await request.get(url).agent(agent).timeout({ deadline: 30000 });
  return res.body;
} catch (err) {
  if (err.status === 407) throw new Error("Proxy rejected credentials");
  if (err.status === 401) throw new Error("Target requires authentication");
  if (!err.status) throw new Error(`Network error: ${err.code} ${err.message}`);
  throw err;
}

Vale a pena ter em conta a distinção entre 407 e 401. Um 407 significa que o proxy bloqueou o acesso e que o destino nunca foi alcançado; um 401 significa que o proxy funcionou e que o destino requer credenciais. São situações diferentes, com soluções diferentes, e são facilmente confundíveis quando ambas aparecem como erros lançados.

Um erro sem err.status significa que não chegou qualquer resposta HTTP, o que aponta para a ligação e não para a autenticação de alguém. ECONNREFUSED significa que nada está a ouvir no endereço do proxy; ETIMEDOUT significa que os pacotes estão a desaparecer.

Para tratar alguns códigos de erro como sucessos — interpretando um 404 como dados em vez de uma falha — utilize .ok():

.ok(res => res.status < 500)

Tentativas de repetição: com cuidado

O SuperAgent possui uma funcionalidade de repetição integrada, com uma restrição documentada que vale a pena respeitar.

const res = await request.get(url).agent(agent).retry(2);

A documentação explica que .retry() «irá repetir automaticamente as solicitações, caso estas falhem de forma transitória ou devido a uma ligação à Internet instável», aceitando um número opcional de tentativas (padrão 1) e uma função de retorno de chamada invocada «antes de cada nova tentativa». A função de retorno «pode devolver true/false para controlar se a solicitação deve ser repetida (mas o número máximo de tentativas é sempre aplicado)».

E a restrição, claramente indicada na documentação: utilize .retry() «apenas com solicitações que sejam idempotentes».

Através de um proxy, isto é mais importante do que o habitual, por uma razão específica. Um timeout não é prova de falha — a solicitação pode ter chegado ao destino e sido bem-sucedida, enquanto a resposta se perdeu no caminho de volta. Existe um salto adicional onde isso pode acontecer. Repetir uma chamada POST nessa situação pode duplicar uma gravação, e nenhuma configuração de repetição torna isso seguro. Quando a operação for importante, utilize uma chave de idempotência, se a API a disponibilizar.

O callback é também o local certo para evitar repetir uma tentativa após uma falha de autenticação, uma vez que um erro 407 com credenciais erradas produzirá um 407 em todas as tentativas:

.retry(3, (err, res) => {
  if (res?.status === 407 || res?.status === 401) return false;
  return true;
})

Um wrapper que vale a pena escrever

O encadeamento do SuperAgent é feito por pedido, o que significa que é fácil esquecer a configuração do proxy naquela chamada que realmente importa. Envolver a criação do pedido resolve esse problema e oferece um local onde colocar o resto das predefinições.

import request from "superagent";
import { ProxyAgent } from "proxy-agent";

const agent = process.env.PROXY_URL ? new ProxyAgent(process.env.PROXY_URL) : undefined;

const UA = "AcmeBot/1.0 (+https://acme.example.com/bot)";

function req(method, url) {
  const r = request[method](url)
    .set("User-Agent", UA)
    .timeout({ response: 15000, deadline: 60000 })
    .retry(2, (err, res) => {
      if (res?.status === 407 || res?.status === 401) return false;
      if (res?.status === 429) return false;   // honour the rate limit instead
      return true;
    });
  return agent ? r.agent(agent) : r;
}

export const get = url => req("get", url);
export const post = url => req("post", url);

export async function verifyExit() {
  const res = await get("https://api.ipify.org?format=json");
  console.log(`Exit address: ${res.body.ip}`);
  return res.body.ip;
}

As cinco opções apresentadas foram escolhidas deliberadamente.

O proxy é opcional e provém do ambiente. Sem PROXY_URL, o agente é undefined e as solicitações são encaminhadas diretamente, o que faz com que o desenvolvimento local e a produção se comportem de forma previsível, sem ramificações no código da aplicação. Nenhuma credencial aparece no código-fonte.

ProxyAgent sem nenhum argumento no construtor seria interpretado como http_proxy e similares, caso prefira uma configuração orientada pelo ambiente; passar o URL explicitamente torna a fonte de verdade óbvia, o que normalmente tem mais valor.

O agente do utilizador é honesto e inclui um URL de contacto. Não custa nada e altera o que acontece quando um operador do site repara em si.

As tentativas de repetição excluem os estados em que repetir a tentativa é inútil ou indelicado. Um 407 com credenciais inválidas será sempre um 407; um 429 é uma instrução para abrandar, e tentar novamente converte um limite temporário num limite mais prolongado.

O ficheiroverifyExit() é exportado e chamado no arranque. Seis linhas que transformam um proxy silenciosamente contornado numa entrada nos registos — o que é o único tema recorrente do funcionamento do proxy em todos os clientes, e a única coisa que nenhuma biblioteca fará por si.

O «.connect()» não é um proxy

Vale a pena destacar isto porque parece ser um proxy, mas não é.

O SuperAgent disponibiliza um método «.connect()» que, de acordo com a documentação, permite «ignorar a resolução DNS e direcionar todos os pedidos para um endereço IP específico». Suporta um mapeamento, incluindo um fallback «*»:

const res = await request.get("http://redir.example.com:555")
  .connect({
    "redir.example.com": "127.0.0.1",
    "www.example.com": false,
    "mapped.example.com": { host: "127.0.0.1", port: 8080 },
    "*": "proxy.example.com",
  });

A documentação refere que «as solicitações manterão o seu cabeçalho Host com o valor original» e que .connect(undefined) desativa esta funcionalidade.

Trata-se de redirecionamento de host, não de proxy. Altera o endereço para o qual a ligação é estabelecida, mantendo a solicitação inalterada — não há nenhum túnel CONNECT, nenhum protocolo de proxy nem autenticação de proxy. Existe para fins de teste e a documentação coloca-a na secção «Testes no localhost» por uma boa razão.

A linha «"*": "proxy.example.com"» no exemplo oficial é a fonte da confusão. Utilize «.connect()» para direcionar os pedidos para um servidor de teste local; utilize um agente para um proxy real.

Perguntas frequentes

Como utilizo um proxy com o SuperAgent?

Passe um agente proxy para o .agent(): crie um HttpsProxyAgent ou um SocksProxyAgent com o URL do seu proxy e passe-o para o pedido. Em alternativa, utilize a extensão superagent-proxy, que adiciona um método .proxy(uri) — embora esse pacote não tenha sido lançado desde 2021.

Qual é a diferença entre .agent() com e sem argumentos?

Sem argumentos, cria uma cópia do SuperAgent com persistência de cookies, com o seu próprio ficheiro jar e opções predefinidas. Com um argumento, define o parâmetro http.Agent do Node para essa solicitação, sendo essa a forma como o suporte ao proxy é aplicado. O nome comum causa uma verdadeira confusão.

O superagent-proxy ainda é mantido?

Não está obsoleto, mas a versão 3.0.0 data de setembro de 2021, enquanto a sua dependência subjacente proxy-agent continuou a ser lançada — mais recentemente em junho de 2026. Para código novo, utilizar um agente proxy diretamente evita um wrapper desatualizado, com o custo de apenas uma linha adicional.

Porque é que o meu proxy do SuperAgent não está a funcionar?

Na maioria das vezes, porque .agent() foi chamado sem nenhum argumento, o que cria um «cookie jar» em vez de configurar um proxy. Verifique também se o agente foi aplicado à solicitação correta, uma vez que o encadeamento do SuperAgent é feito por chamada. Verifique solicitando um serviço que indique o seu endereço — um proxy contornado não produz nenhum erro.

O SuperAgent respeita as variáveis de ambiente HTTP_PROXY?

Por si só, não. O pacote proxy-agent lê http_proxy, https_proxy e no_proxy; por isso, criar um ProxyAgent() sem argumentos e passá-lo para .agent() proporciona-lhe um comportamento orientado pelo ambiente.

Como defino os tempos de espera para pedidos encaminhados por proxy?

Utilize ambas as definições: .timeout({ response: 15000, deadline: 60000 }). O tempo de espera da resposta limita a espera pelo primeiro byte, enquanto o prazo limite restringe todo o pedido. Defina-os com base em medições realizadas através do proxy, uma vez que uma saída residencial acrescenta latência real às fases de DNS, ligação e TLS.

Como distinguir um erro de proxy de um erro no destino?

Pelo código de estado. O SuperAgent trata os códigos 4xx e 5xx como erros, por isso detete e analise err.status — 407 significa que o proxy rejeitou o pedido e o destino nunca foi alcançado, enquanto 401 significa que o proxy funcionou e o destino requer credenciais. A ausência total de «err.status» significa que não chegou qualquer resposta HTTP.

Posso utilizar o .connect() como proxy?

Não. Este redireciona os pedidos para um IP específico, mantendo o cabeçalho «Host» original, o que corresponde a um mapeamento de host para fins de teste e não a um proxy. Não existe túnel, nem protocolo de proxy, nem autenticação. Utilize um agente para um proxy verdadeiro.

Conclusão

O SuperAgent não dispõe de uma opção de proxy própria, pelo que a escolha recai sobre um agente ou uma extensão — e o agente é a melhor opção por predefinição, uma vez que, em ambos os casos, são os pacotes mantidos que realizam o trabalho efetivo.

A terminologia é a principal armadilha. .agent() sem nenhum argumento fornece-lhe um «cookie jar»; .agent(something) define um agente HTTP. As pessoas configuram o primeiro, vêem que os pedidos são bem-sucedidos e concluem que o proxy está a funcionar. Ninguém as corrige, porque um proxy contornado falha silenciosamente, por definição.

O que torna a verificação um hábito que vale a pena cultivar. Solicite um serviço que indique o seu endereço, com e sem o agente, e confirme se a resposta muda. Para trabalhos com segmentação geográfica, vá mais longe e confirme se o conteúdo regionalmente distinto difere realmente — o endereço é a parte fácil e a menos informativa.

Em seguida, defina ambos os tempos de espera, utilize o «err.status» para que um 407 e um 401 conduzam a mensagens diferentes e mantenha o «.retry()» afastado de tudo o que não seja idempotente. Através de um proxy, existe um salto adicional em que uma solicitação bem-sucedida pode perder a sua resposta, e uma nova tentativa nessa situação é uma duplicação, em vez de uma recuperação.