
Configurando Proxy no NodeJS
Recentemente, um projeto exigia que o NodeJS usasse um proxy. Inicialmente pensei que seria uma configuração simples, mas acabou sendo bastante desafiador.
O NodeJS não lê os proxies do sistema por padrão, e como o NodeJS tem múltiplos métodos para enviar requisições de rede, as formas de configurar proxies também variam. Aqui está um resumo.
Pré-requisitos
Vamos assumir que os endereços do servidor proxy vêm de variáveis de ambiente, que é a prática padrão para muitos aplicativos web. Por conveniência, vamos chamá-los de HTTP_PROXY
e HTTPS_PROXY
.
Fetch
Versões recentes do NodeJS suportam a interface Fetch, que tenta manter consistência com o Fetch do navegador, mas se fosse completamente consistente, não haveria como configurar proxies. Felizmente, o NodeJS abriu uma porta dos fundos ao adicionar um parâmetro único dispatcher
para modificar parâmetros de requisição de rede, incluindo servidores proxy.
Podemos usar o pacote undici
para configurar o dispatcher
:
npm install undici
Configurando proxy para fetch
Use ProxyAgent para configurar:
import { ProxyAgent } from "undici";
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
await fetch(url, { dispatcher: new ProxyAgent(proxyUrl) });
}
Configuração global de proxy para fetch
setGlobalDispatcher
é usado para configurar proxies para todas as chamadas fetch no programa NodeJS:
import { setGlobalDispatcher, ProxyAgent } from "undici";
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
setGlobalDispatcher(new ProxyAgent(proxyUrl));
}
Para remover o proxy, você pode definir um Agent vazio:
import { Agent, setGlobalDispatcher } from "undici";
setGlobalDispatcher(new Agent());
Como funciona
setGlobalDispatcher
na verdade usa um ponto de entrada oculto no NodeJS. O objeto global no NodeJS tem um Symbol para definir o dispatcher global:
global[Symbol.for("undici.globalDispatcher.1")] = yourDispatcher;
Isso não parece estar documentado no NodeJS (pelo menos não consegui encontrar). Para mais detalhes, veja: https://github.com/nodejs/node/issues/43187
O que mais o dispatcher pode fazer além de configurar proxies
Se você importar Agent
em vez de ProxyAgent
, também pode configurar parâmetros de rede como keepAlive e timeout:
import { Agent } from "undici";
const res = await fetch("https://example.com", {
dispatcher: new Agent({
keepAliveTimeout: 10,
keepAliveMaxTimeout: 10,
}),
});
const json = await res.json();
console.log(json);
Para mais detalhes, consulte a documentação do undici.
Módulos nativos do NodeJS http e https
Como mencionado acima, o NodeJS não tem métodos incorporados para configurar proxies, então precisamos desenvolvê-los usando http.Agent
e https.Agent
. Atualmente, os pacotes populares são http-proxy-agent
e https-proxy-agent
.
Aqui está um exemplo usando https-proxy-agent:
import https from "https";
import { HttpsProxyAgent } from "https-proxy-agent";
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (proxyUrl) {
const agent = new HttpsProxyAgent(proxyUrl);
https.get(
{
host: "example.com",
path: "/",
agent,
},
(res) => {
// Processar resposta
}
);
}
Axios
O Axios é quase o padrão da indústria para JavaScript. Ele tem múltiplas formas de configurar proxies (em ordem de prioridade do menor para o maior):
-
Variáveis de ambiente: O próprio Axios lê as variáveis de ambiente
HTTP_PROXY
eHTTPS_PROXY
-
Parâmetro
proxy
:import axios from "axios"; axios.get("https://example.com", { proxy: { host: "127.0.0.1", port: 7890, }, });
-
Parâmetros
httpAgent
ehttpsAgent
: Você pode passar oshttp.Agent
ehttps.Agent
incorporados do NodeJS para controlar parâmetros de rede.Aqui usamos os
http-proxy-agent
ehttps-proxy-agent
mencionados na seção anterior:import axios from "axios"; import { HttpsProxyAgent } from "https-proxy-agent"; import { HttpProxyAgent } from "http-proxy-agent"; const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY; if (proxyUrl) { const httpsAgent = new HttpsProxyAgent(proxyUrl); const httpAgent = new HttpProxyAgent(proxyUrl); const instance = axios.create({ httpAgent, httpsAgent, }); }
Para mais detalhes, consulte a documentação do Axios.
Limitações de conexão HTTPS
Descobri que se você configurar um proxy HTTP usando os dois primeiros métodos, o Axios não consegue estabelecer conexões HTTPS. A razão é que o Axios não envia o método CONNECT, então não consegue estabelecer conexões TLS (se você não entende o método CONNECT, pode ler este artigo).