Por que Usar Proxies em Deno e Bun é Diferente do Node.js
Se você veio do Node.js, provavelmente está acostumado a bibliotecas como https-proxy-agent ou undici para rotear fetch() através de um proxy. Deno e Bun, porém, implementam fetch() nativamente — e por padrão ignoram variáveis de ambiente de proxy e qualquer configuração global. O motivo é simples: a especificação Fetch do WHATWG não define um mecanismo de proxy nativo, deixando cada runtime livre para resolver isso à sua maneira.
Isso significa que copiar um exemplo de Node.js para Deno ou Bun e esperar que o proxy funcione não vai funcionar. Você precisa usar a API específica de cada runtime. A boa notícia é que ambas as abordagens são mais limpas que no Node: Deno expõe Deno.createHttpClient({ proxy }), e Bun suporta fetch(url, { proxy }) diretamente — uma linha, sem dependências extras.
Para quem faz scraping de SERPs, monitoramento de preços, ou coleta de dados para IA, dominar usar proxies em Deno e Bun é essencial para rodar pipelines HTTP concorrentes com IPs residenciais rotativos, sem ser bloqueado nos primeiros 50 requests.
Contexto Técnico: Como Cada Runtime Resolve o Proxy
Deno: Deno.createHttpClient + fetch(url, { client })
Deno trata proxies como uma propriedade do cliente HTTP, não do request global. Você cria um cliente configurado com Deno.createHttpClient() e o passa como opção client em fetch(). Esse cliente é reutilizável, suporta certificados CA customizados, e aceita autenticação Basic inline na URL do proxy.
Segundo a documentação oficial do Deno, o campo proxy aceita { url: string, basicAuth?: { username, password } }. A URL do proxy deve incluir o esquema (http:// ou socks5://).
Bun: fetch(url, { proxy }) nativo
Bun é ainda mais direto: o segundo argumento de fetch() aceita uma string proxy no formato http://user:pass@host:port. Não há cliente separado para configurar. Para proxies SOCKS5, use socks5:// como esquema.
| Aspecto | Deno | Bun |
|---|---|---|
| API de proxy | Deno.createHttpClient({ proxy }) + { client } | fetch(url, { proxy: string }) |
| SOCKS5 | Sim, via socks5:// na URL | Sim, via socks5:// na URL |
| Reuso de conexão | Cliente reutilizável | Automático por URL base |
| CA customizado | caCerts no cliente | BUN_CA_BUNDLE_PATH env |
| Dependências extras | Nenhuma | Nenhuma |
Exemplo Básico: HTTP Proxy com ProxyHat em Deno
Configuração mínima usando o gateway HTTP do ProxyHat na porta 8080:
// deno run --allow-net proxy_basics.ts
const proxyUrl = "http://user-country-US:pass@gate.proxyhat.com:8080";
const client = Deno.createHttpClient({
proxy: {
url: proxyUrl,
// basicAuth é opcional se já está na URL
},
});
try {
const res = await fetch("https://httpbin.org/ip", { client });
const body = await res.text();
console.log("IP de saída:", body);
} catch (err) {
console.error("Erro no fetch via proxy:", err);
} finally {
client.close(); // libera recursos do cliente
}
Note o padrão de username user-country-US: o ProxyHat codifica geo-targeting e sticky sessions diretamente no campo de usuário, sem headers extras.
Exemplo Básico: HTTP Proxy com ProxyHat em Bun
// bun run proxy_basics.ts
const proxy = "http://user-country-DE:pass@gate.proxyhat.com:8080";
try {
const res = await fetch("https://httpbin.org/ip", { proxy });
const data = await res.json();
console.log("IP de saída:", data.origin);
} catch (err) {
console.error("Erro no fetch via proxy:", err);
}
Uma linha. Sem createHttpClient, sem close. Para casos simples, Bun é mais ergonômico; para pipelines complexos com reuso de conexão e CA customizado, Deno oferece controle mais granular.
Geo-Targeting e Sticky Sessions no Username
O ProxyHat suporta flags no username para controlar país, cidade e sessão. Isso é mais confiável que headers customizados porque o gateway interpreta o username antes de rotear o request.
// Deno: sticky session por cidade
const proxyUrl =
"http://user-country-DE-city-berlin-session-abc123:pass@gate.proxyhat.com:8080";
const client = Deno.createHttpClient({
proxy: { url: proxyUrl },
});
// Todos os requests com este cliente saem pelo mesmo IP em Berlim
const res = await fetch("https://httpbin.org/headers", { client });
console.log(await res.json());
client.close();
Para SOCKS5, troque a porta para 1080 e o esquema:
// Bun: SOCKS5 proxy
const proxy = "socks5://user-country-US-session-sess01:pass@gate.proxyhat.com:1080";
const res = await fetch("https://httpbin.org/ip", { proxy });
console.log(await res.text());
Use SOCKS5 quando precisar tunelar tráfego não-HTTP (gRPC, WebSockets via proxy, conexões TCP raw) ou quando o alvo bloqueia proxies HTTP transparentes. Para scraping HTTP/HTTPS comum, a porta 8080 é suficiente e geralmente mais rápida.
Variáveis de Ambiente HTTP_PROXY / HTTPS_PROXY
Deno respeita HTTP_PROXY e HTTPS_PROXY apenas quando você não passa client explícito em fetch(). Bun, por outro lado, não lê essas variáveis automaticamente — você precisa passar proxy explicitamente ou usar um wrapper.
// Deno: proxy via env var (sem cliente explícito)
// export HTTP_PROXY=http://user-country-US:pass@gate.proxyhat.com:8080
// deno run --allow-net --allow-env app.ts
// Sem passar { client }, Deno usa HTTP_PROXY automaticamente
const res = await fetch("https://httpbin.org/ip");
console.log(await res.text());
Quando preferir variáveis de ambiente: scripts CLI descartáveis, testes rápidos, ou quando você não pode modificar o código que faz fetch(). Quando preferir configuração por cliente: pipelines de produção com múltiplos pools de proxy, geo-targeting diferente por request, ou quando precisa de CA customizado por cliente.
Rotação de Sticky Sessions com Concorrência
Para alvos com anti-bot agressivo (SERPs do Google, e-commerce, redes sociais), você precisa de IPs residenciais com rotação. A estratégia: criar um pool de sticky sessions, cada uma com um ID único, e distribuir requests concorrentes entre elas usando Promise.all com timeout via AbortController.
// Deno: pool de sticky sessions com timeout e retries
interface ProxyResult {
session: string;
status: number;
body: string;
}
function buildProxyUrl(sessionId: string, country = "US"): string {
return `http://user-country-${country}-session-${sessionId}:pass@gate.proxyhat.com:8080`;
}
async function fetchWithRetry(
url: string,
sessionId: string,
maxRetries = 3,
timeoutMs = 10000,
): Promise<ProxyResult> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
const client = Deno.createHttpClient({
proxy: { url: buildProxyUrl(sessionId) },
});
try {
const res = await fetch(url, { client, signal: controller.signal });
const body = await res.text();
clearTimeout(timeout);
client.close();
return { session: sessionId, status: res.status, body };
} catch (err) {
clearTimeout(timeout);
client.close();
if (attempt === maxRetries - 1) throw err;
// Backoff exponencial: 500ms, 1000ms, 2000ms
await new Promise((r) => setTimeout(r, 500 * 2 ** attempt));
}
}
throw new Error("Unreachable");
}
// Pool de 5 sticky sessions
const sessions = ["sess01", "sess02", "sess03", "sess04", "sess05"];
const targetUrl = "https://httpbin.org/ip";
const results = await Promise.all(
sessions.map((s) => fetchWithRetry(targetUrl, s)),
);
for (const r of results) {
console.log(`Session ${r.session}: HTTP ${r.status} → ${r.body.trim()}`);
}
Cada sticky session mantém o mesmo IP por padrão por até 30 minutos (dependendo da configuração do provedor). Com 5 sessions e Promise.all, você dispara 5 requests concorrentes, cada um por um IP diferente. Se um falhar, o retry usa backoff exponencial para evitar sobrecarregar o gateway.
Por que Proxies Residenciais para Alvos de Alto Bloqueio
Datacenter proxies são baratos, mas faixas de IP de datacenter (AWS, DigitalOcean, Hetzner) são frequentemente bloqueadas por serviços como Google, Amazon, e Cloudflare. Proxies residenciais usam IPs de ISPs reais, tornando o tráfego indistinguível de um usuário doméstico.
Em benchmarks típicos de scraping de SERPs, proxies datacenter atingem taxas de sucesso de 20–40% contra anti-bot moderno, enquanto residenciais mantêm 85–95%. A contrapartida é latência: residenciais adicionam 100–300ms por request versus 10–50ms de datacenter. Para scraping em escala, esse trade-off vale a pena — um request bloqueado custa mais que um request lento.
Para casos de uso específicos, veja web scraping e SERP tracking na documentação do ProxyHat.
Produção: CA Customizado, Reuso de Conexão e Circuit Breaker
CA Customizado no Deno
Se o alvo usa um certificado auto-assinado ou um CA interno, passe o certificado via caCerts:
// Deno: cliente com CA customizado + proxy
const caCert = await Deno.readTextFile("./custom-ca.pem");
const client = Deno.createHttpClient({
proxy: {
url: "http://user-country-US:pass@gate.proxyhat.com:8080",
},
caCerts: [caCert],
});
const res = await fetch("https://internal.example.com/api", { client });
console.log(await res.text());
client.close();
Reuso de Cliente vs. Cliente por Request
Em Deno, reutilizar o mesmo Deno.createHttpClient para múltiplos requests com o mesmo proxy melhora performance por reuso de conexão TCP. No entanto, se você está rotacionando proxies (sticky sessions diferentes), crie um cliente por session e feche-o ao finalizar o batch.
Circuit Breaker Simples
// Bun: circuit breaker com contador de falhas
class ProxyCircuitBreaker {
private failures = new Map<string, number>();
private threshold = 5;
private resetMs = 60000;
canUse(session: string): boolean {
const fails = this.failures.get(session) ?? 0;
return fails < this.threshold;
}
recordFailure(session: string): void {
const fails = (this.failures.get(session) ?? 0) + 1;
this.failures.set(session, fails);
if (fails >= this.threshold) {
setTimeout(() => this.failures.delete(session), this.resetMs);
}
}
recordSuccess(session: string): void {
this.failures.delete(session);
}
}
const breaker = new ProxyCircuitBreaker();
async function safeFetch(url: string, sessionId: string): Promise<string> {
if (!breaker.canUse(sessionId)) {
throw new Error(`Circuit aberto para session ${sessionId}`);
}
const proxy = `http://user-country-US-session-${sessionId}:pass@gate.proxyhat.com:8080`;
try {
const res = await fetch(url, { proxy });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
breaker.recordSuccess(sessionId);
return await res.text();
} catch (err) {
breaker.recordFailure(sessionId);
throw err;
}
}
Side-by-Side: ProxyHat Node SDK vs. Fetch Nativo
O ProxyHat oferece um SDK para Node.js que também roda sob Deno (via npm: specifier) e Bun (compatibilidade nativa com npm). O SDK abstrai rotação, retries e geo-targeting, mas para casos simples, fetch nativo é mais leve e não adiciona dependências.
// Deno: ProxyHat SDK via npm specifier
// import { ProxyHat } from "npm:@proxyhat/sdk";
// const ph = new ProxyHat({
// username: "user",
// password: "pass",
// country: "US",
// });
//
// const ip = await ph.fetch("https://httpbin.org/ip");
// console.log(await ip.text());
// Equivalente com fetch nativo (sem SDK):
const client = Deno.createHttpClient({
proxy: {
url: "http://user-country-US:pass@gate.proxyhat.com:8080",
},
});
const res = await fetch("https://httpbin.org/ip", { client });
console.log(await res.text());
client.close();
Use o SDK quando precisar de rotação automática, métricas integradas, ou quando a equipe prefere uma API consistente entre projetos. Use fetch nativo quando quiser zero dependências, controle total do ciclo de vida do cliente, ou estiver em ambientes com restrições de pacotes npm.
Para detalhes completos de configuração, consulte a documentação oficial do ProxyHat e a página de preços.
Considerações Éticas e Legais
Scraping de dados públicos é geralmente legal, mas o contexto importa. Nos EUA, o Computer Fraud and Abuse Act (CFAA) criminaliza acesso não autorizado a sistemas protegidos — embora decisões recentes (como hiQ Labs v. LinkedIn) tenham limitado sua aplicação a scraping de dados públicos. Na UE, o GDPR regula o processamento de dados pessoais, e scraping de dados pessoais sem base legal pode violar a lei.
Boas práticas:
- Use APIs oficiais quando disponíveis — são mais confiáveis e legalmente mais seguras.
- Respeite
robots.txte os Termos de Serviço do alvo. - Limite a taxa de requests (rate limiting) para não sobrecarregar o servidor.
- Colete apenas dados públicos, não dados pessoais protegidos.
- Considere o impacto: scraping agressivo pode degradar o serviço para outros usuários.
Key Takeaways
1. Deno e Bun não herdam proxy de variáveis de ambiente por padrão — Deno usa
Deno.createHttpClient({ proxy })+{ client }em fetch; Bun usafetch(url, { proxy: string })nativo.2. O ProxyHat codifica geo-targeting e sticky sessions no username:
user-country-US-session-abc123. Use a porta8080para HTTP e1080para SOCKS5.3. Para alvos de alto bloqueio, use proxies residenciais com pool de sticky sessions,
Promise.allpara concorrência, eAbortControllerpara timeout.4. Em produção, adicione retries com backoff exponencial, circuit breaker, e feche clientes Deno após uso para liberar conexões.
5. Sempre verifique
robots.txt, ToS, e conformidade com CFAA/GDPR antes de coletar dados.
Perguntas Frequentes
O que significa usar proxies em Deno e Bun?
Significa configurar o roteamento de tráfego HTTP/HTTPS através de um servidor proxy nos runtimes Deno e Bun. Diferente do Node.js, que depende de bibliotecas como https-proxy-agent, Deno usa Deno.createHttpClient({ proxy }) e Bun suporta fetch(url, { proxy }) nativamente, sem dependências extras.
Por que usar proxies em Deno e Bun importa para usuários de proxy?
Porque esses runtimes são cada vez mais usados para scraping, automação e pipelines de dados em TypeScript. Sem configuração correta de proxy, o tráfego sai pelo IP do servidor, que é facilmente bloqueado. Proxies residenciais com geo-targeting e sticky sessions permitem distribuir requests por IPs de ISPs reais, aumentando a taxa de sucesso de 20–40% (datacenter) para 85–95% (residencial).
Qual tipo de proxy funciona melhor para Deno e Bun?
Proxies residenciais HTTP na porta 8080 são a melhor escolha para a maioria dos casos de scraping e automação. SOCKS5 na porta 1080 é preferível para tráfego não-HTTP (gRPC, TCP raw) ou quando o alvo bloqueia proxies HTTP transparentes. Datacenter proxies são aceitáveis para alvos sem anti-bot, mas têm taxas de bloqueio significativamente maiores.
Como evitar bloqueios ao implementar proxies em Deno e Bun?
Use sticky sessions com IDs únicos para manter consistência de IP por sessão, rotacione entre múltiplas sessions com Promise.all, adicione timeout via AbortController, implemente retries com backoff exponencial, e respeite rate limits do alvo. Combine com geo-targeting no username (user-country-US-session-abc123) para parecer tráfego local legítimo.
O Deno.createHttpClient é reutilizável entre requests?
Sim. O cliente criado por Deno.createHttpClient pode ser passado em múltiplas chamadas de fetch(), reutilizando conexões TCP. Para rotação de proxy (sessions diferentes), crie um cliente por session e chame client.close() ao terminar para liberar recursos.






