Configurar proxies HTTP em Java não é tão direto quanto em linguagens como Python ou Node.js. A plataforma oferece múltiplas APIs de cliente HTTP — java.net.http.HttpClient (desde o Java 11), OkHttp, Apache HttpClient, e bibliotecas de scraping como Jsoup — cada uma com sua própria abordagem para proxy. Este guia mostra como configurar proxies autenticados, lidar com rotação de IPs, e construir aplicações de scraping robustas em Java 17+.
Por que usar proxies HTTP em aplicações Java?
Aplicações Java que fazem requisições HTTP frequentemente precisam de proxies por três motivos principais:
- Rate limiting: APIs e sites limitam requisições por IP. Proxies residenciais permitem distribuir requisições.
- Geo-targeting: Acessar conteúdo restrito por região usando IPs de países específicos.
- Anonimato: Evitar bloqueios em scraping de dados públicos.
O Java 17+ oferece APIs modernas, mas a integração com proxies autenticados requer configuração específica. Vamos cobrir cada cliente HTTP popular.
Java 11+ HttpClient com ProxySelector e Authenticator
O java.net.http.HttpClient introduzido no Java 11 é o cliente HTTP moderno padrão. Ele suporta HTTP/2, WebSocket, e APIs reativas. Para usar proxies, você precisa configurar um ProxySelector e, para autenticação, um Authenticator.
Configuração básica com ProxySelector
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
public class HttpClientProxyExample {
private static final String PROXY_HOST = "gate.proxyhat.com";
private static final int PROXY_PORT = 8080;
public static void main(String[] args) throws Exception {
// Criar ProxySelector que direciona todas as requisições pelo proxy
ProxySelector proxySelector = new ProxySelector() {
@Override
public List<Proxy> select(URI uri) {
return List.of(new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(PROXY_HOST, PROXY_PORT)));
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException e) {
System.err.println("Falha na conexão proxy: " + e.getMessage());
}
};
HttpClient client = HttpClient.newBuilder()
.proxy(proxySelector)
.connectTimeout(Duration.ofSeconds(30))
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/ip"))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Body: " + response.body());
}
}
Autenticação de proxy com Authenticator
Proxies comerciais como ProxyHat exigem autenticação. O HttpClient usa Authenticator para fornecer credenciais:
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.http.HttpClient;
public class HttpClientAuthenticatedProxy {
private static final String PROXY_HOST = "gate.proxyhat.com";
private static final int PROXY_PORT = 8080;
private static final String USERNAME = "user-country-BR"; // Geo-targeting Brasil
private static final String PASSWORD = "sua_senha";
public static HttpClient createClient() {
Authenticator auth = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() == RequestorType.PROXY) {
return new PasswordAuthentication(USERNAME, PASSWORD.toCharArray());
}
return null;
}
};
ProxySelector proxySelector = ProxySelector.of(
new InetSocketAddress(PROXY_HOST, PROXY_PORT));
return HttpClient.newBuilder()
.proxy(proxySelector)
.authenticator(auth)
.connectTimeout(Duration.ofSeconds(30))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
}
public static void main(String[] args) throws Exception {
HttpClient client = createClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/ip"))
.timeout(Duration.ofSeconds(60))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
Nota: OAuthenticatorverificagetRequestorType()para diferenciar entre autenticação de proxy (PROXY) e autenticação do servidor destino (SERVER). Isso é essencial quando ambos exigem credenciais.
Requisições assíncronas com CompletableFuture
import java.util.concurrent.CompletableFuture;
import java.util.List;
import java.util.stream.Collectors;
public class AsyncProxyRequests {
private final HttpClient client;
public AsyncProxyRequests() {
this.client = HttpClientAuthenticatedProxy.createClient();
}
public CompletableFuture<HttpResponse<String>> fetchAsync(String url) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
}
public void fetchMultiple(List<String> urls) {
List<CompletableFuture<HttpResponse<String>>> futures = urls.stream()
.map(this::fetchAsync)
.collect(Collectors.toList());
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenAccept(v -> {
futures.forEach(f -> {
try {
HttpResponse<String> resp = f.get();
System.out.println(resp.uri() + " -> " + resp.statusCode());
} catch (Exception e) {
System.err.println("Erro: " + e.getMessage());
}
});
})
.join();
}
public static void main(String[] args) {
AsyncProxyRequests scraper = new AsyncProxyRequests();
List<String> urls = List.of(
"https://httpbin.org/ip",
"https://httpbin.org/headers",
"https://httpbin.org/user-agent"
);
scraper.fetchMultiple(urls);
}
}
OkHttp com Proxy e Authenticator
OkHttp da Square é amplamente usado no ecossistema Android e backend Java. Sua API é mais intuitiva para configuração de proxies comparada ao HttpClient nativo.
Configuração básica com proxy autenticado
import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.TimeUnit;
public class OkHttpProxyExample {
private static final String PROXY_HOST = "gate.proxyhat.com";
private static final int PROXY_PORT = 8080;
private static final String USERNAME = "user-country-US";
private static final String PASSWORD = "sua_senha";
public static OkHttpClient createClient() {
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(PROXY_HOST, PROXY_PORT));
Authenticator proxyAuthenticator = new Authenticator() {
@Override
public Request authenticate(Route route, Response response) {
// Evitar loop infinito de autenticação
if (response.responseCount() >= 3) {
return null;
}
String credential = Credentials.basic(USERNAME, PASSWORD);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
};
return new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator(proxyAuthenticator)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
}
public static void main(String[] args) throws Exception {
OkHttpClient client = createClient();
Request request = new Request.Builder()
.url("https://httpbin.org/ip")
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println("Status: " + response.code());
System.out.println("Body: " + response.body().string());
}
}
}
Pool de conexões e configuração avançada
OkHttp gerencia automaticamente um pool de conexões. Para aplicações de alto volume, configure o ConnectionPool explicitamente:
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.util.concurrent.TimeUnit;
public class OkHttpConnectionPool {
public static OkHttpClient createOptimizedClient() {
// Pool com 50 conexões idle, timeout de 5 minutos
ConnectionPool connectionPool = new ConnectionPool(50, 5, TimeUnit.MINUTES);
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress("gate.proxyhat.com", 8080));
return new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator((route, response) -> {
String credential = Credentials.basic("user-country-DE", "sua_senha");
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
})
.connectionPool(connectionPool)
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
// Interceptor para logging
.addInterceptor(chain -> {
long start = System.nanoTime();
Request request = chain.request();
Response response = chain.proceed(request);
long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
System.out.printf("[%dms] %s -> %d%n",
elapsed, request.url(), response.code());
return response;
})
.build();
}
}
Jsoup com suporte a proxy para parsing HTML
Jsoup é a biblioteca padrão para parsing HTML em Java. Ela pode buscar URLs diretamente, com suporte a proxies via Connection.
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.Proxy;
import java.net.InetSocketAddress;
public class JsoupProxyExample {
private static final String PROXY_HOST = "gate.proxyhat.com";
private static final int PROXY_PORT = 8080;
private static final String USERNAME = "user-country-BR";
private static final String PASSWORD = "sua_senha";
public static Document fetchWithProxy(String url) throws Exception {
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(PROXY_HOST, PROXY_PORT));
return Jsoup.connect(url)
.proxy(proxy)
.header("Proxy-Authorization",
java.util.Base64.getEncoder().encodeToString(
(USERNAME + ":" + PASSWORD).getBytes()))
.timeout(30000)
.followRedirects(true)
.ignoreHttpErrors(true)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) " +
"Chrome/120.0.0.0 Safari/537.36")
.get();
}
public static void main(String[] args) throws Exception {
Document doc = fetchWithProxy("https://example.com");
// Extrair links
Elements links = doc.select("a[href]");
for (Element link : links) {
System.out.println(link.attr("abs:href") + " - " + link.text());
}
// Extrair metadados
String title = doc.title();
String description = doc.select("meta[name=description]").attr("content");
System.out.println("Title: " + title);
System.out.println("Description: " + description);
}
}
Integração Jsoup + OkHttp para maior controle
Para aplicações de produção, combine OkHttp (para requisições robustas) com Jsoup (para parsing):
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class JsoupOkHttpIntegration {
private final OkHttpClient httpClient;
public JsoupOkHttpIntegration() {
this.httpClient = OkHttpProxyExample.createClient();
}
public Document fetchAndParse(String url) throws Exception {
Request request = new Request.Builder()
.url(url)
.header("Accept", "text/html,application/xhtml+xml")
.header("Accept-Language", "pt-BR,pt;q=0.9,en;q=0.8")
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("Falha: " + response.code());
}
String html = response.body().string();
String baseUrl = response.request().url().toString();
// Parse com Jsoup, preservando base URL para links absolutos
return Jsoup.parse(html, baseUrl);
}
}
public static void main(String[] args) throws Exception {
JsoupOkHttpIntegration scraper = new JsoupOkHttpIntegration();
Document doc = scraper.fetchAndParse("https://news.ycombinator.com");
doc.select(".titleline > a").forEach(link -> {
System.out.println(link.text() + " -> " + link.attr("href"));
});
}
}
Apache HttpClient (para ecossistemas legados)
Muitas empresas ainda usam Apache HttpClient 4.x em sistemas legados. A configuração de proxy é mais verbosa:
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class ApacheHttpClientProxy {
private static final String PROXY_HOST = "gate.proxyhat.com";
private static final int PROXY_PORT = 8080;
private static final String USERNAME = "user-country-US";
private static final String PASSWORD = "sua_senha";
public static CloseableHttpClient createClient() {
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(PROXY_HOST, PROXY_PORT),
new UsernamePasswordCredentials(USERNAME, PASSWORD)
);
RequestConfig config = RequestConfig.custom()
.setProxy(proxy)
.setConnectTimeout(30000)
.setSocketTimeout(60000)
.build();
return HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultRequestConfig(config)
.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy())
.build();
}
public static void main(String[] args) throws Exception {
try (CloseableHttpClient client = createClient()) {
HttpGet request = new HttpGet("https://httpbin.org/ip");
try (CloseableHttpResponse response = client.execute(request)) {
String body = EntityUtils.toString(response.getEntity());
System.out.println(body);
}
}
}
}
Scraping paralelo com pool de proxies residenciais
Para scraping de alta escala, use um ExecutorService com rotação de proxies. Este exemplo demonstra como distribuir requisições entre múltiplos IPs:
import java.util.concurrent.*;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
public class ParallelProxyScraper {
private static final String PROXY_HOST = "gate.proxyhat.com";
private static final int PROXY_PORT = 8080;
private static final String BASE_USER = "user-session-";
private static final String PASSWORD = "sua_senha";
private final ExecutorService executor;
private final AtomicInteger sessionCounter = new AtomicInteger(0);
public ParallelProxyScraper(int threadCount) {
this.executor = Executors.newFixedThreadPool(threadCount);
}
private HttpClient createClientWithSession() {
// Cada thread usa uma sessão diferente = IP diferente
String sessionUser = BASE_USER + sessionCounter.getAndIncrement();
Authenticator auth = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() == RequestorType.PROXY) {
return new PasswordAuthentication(sessionUser, PASSWORD.toCharArray());
}
return null;
}
};
ProxySelector proxySelector = ProxySelector.of(
new InetSocketAddress(PROXY_HOST, PROXY_PORT));
return HttpClient.newBuilder()
.proxy(proxySelector)
.authenticator(auth)
.connectTimeout(Duration.ofSeconds(30))
.build();
}
public List<String> scrapeUrls(List<String> urls) {
List<CompletableFuture<String>> futures = new ArrayList<>();
for (String url : urls) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
HttpClient client = createClientWithSession();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(60))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return String.format("[%s] %s -> %d",
Thread.currentThread().getName(),
url,
response.statusCode());
} catch (Exception e) {
return String.format("[ERROR] %s -> %s", url, e.getMessage());
}
}, executor);
futures.add(future);
}
// Aguardar todas as requisições
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
return futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
public static void main(String[] args) {
ParallelProxyScraper scraper = new ParallelProxyScraper(10);
List<String> urls = List.of(
"https://httpbin.org/ip",
"https://httpbin.org/headers",
"https://httpbin.org/user-agent",
"https://httpbin.org/get?query=1",
"https://httpbin.org/get?query=2",
"https://httpbin.org/get?query=3"
);
try {
List<String> results = scraper.scrapeUrls(urls);
results.forEach(System.out::println);
} finally {
scraper.shutdown();
}
}
}
Configuração TLS e SSLContext personalizado
Alguns sites usam certificados não-padronizados ou requerem configurações TLS específicas. O Java usa JSSE (Java Secure Socket Extension) para TLS:
SSLContext personalizado com TrustManager
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.SSLSession;
import java.security.cert.X509Certificate;
import java.net.http.HttpClient;
public class TlsProxyConfig {
// ATENÇÃO: Apenas para desenvolvimento! Não use em produção.
public static SSLContext createTrustAllContext() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
public void checkClientTrusted(X509Certificate[] certs, String t) {}
public void checkServerTrusted(X509Certificate[] certs, String t) {}
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
return sslContext;
}
// Configuração TLS 1.3 para máxima segurança
public static SSLContext createTls13Context() throws Exception {
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, null, new java.security.SecureRandom());
return sslContext;
}
public static HttpClient createTlsClient(SSLContext sslContext) {
ProxySelector proxySelector = ProxySelector.of(
new InetSocketAddress("gate.proxyhat.com", 8080));
Authenticator auth = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() == RequestorType.PROXY) {
return new PasswordAuthentication("user-country-US", "sua_senha".toCharArray());
}
return null;
}
};
return HttpClient.newBuilder()
.proxy(proxySelector)
.authenticator(auth)
.sslContext(sslContext)
.sslParameters(new SSLParameters(new String[]{"TLSv1.3", "TLSv1.2"}))
.connectTimeout(Duration.ofSeconds(30))
.build();
}
public static void main(String[] args) throws Exception {
SSLContext tlsContext = createTls13Context();
HttpClient client = createTlsClient(tlsContext);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/ip"))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
Configurando TLS no OkHttp
import okhttp3.OkHttpClient;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
public class OkHttpTlsConfig {
public static OkHttpClient createTlsClient() throws Exception {
// TrustManager customizado (apenas para desenvolvimento)
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, new X509TrustManager[]{trustManager}, null);
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress("gate.proxyhat.com", 8080));
return new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator((route, response) -> {
String credential = Credentials.basic("user-country-US", "sua_senha");
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
})
.sslSocketFactory(sslContext.getSocketFactory(), trustManager)
.hostnameVerifier((hostname, session) -> true)
.connectTimeout(30, TimeUnit.SECONDS)
.build();
}
}
Connection pooling, timeouts e retry policy
Aplicações de produção precisam de configurações robustas:
HttpClient nativo com retry
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class RobustHttpClient {
private final HttpClient client;
private final ExecutorService executor;
private final int maxRetries;
private final long retryDelayMs;
public RobustHttpClient(int maxRetries, long retryDelayMs) {
this.maxRetries = maxRetries;
this.retryDelayMs = retryDelayMs;
this.executor = Executors.newFixedThreadPool(10);
ProxySelector proxySelector = ProxySelector.of(
new InetSocketAddress("gate.proxyhat.com", 8080));
Authenticator auth = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() == RequestorType.PROXY) {
return new PasswordAuthentication("user-country-US", "sua_senha".toCharArray());
}
return null;
}
};
this.client = HttpClient.newBuilder()
.proxy(proxySelector)
.authenticator(auth)
.executor(executor)
.connectTimeout(Duration.ofSeconds(30))
.followRedirects(HttpClient.Redirect.NORMAL)
.version(HttpClient.Version.HTTP_2)
.build();
}
public CompletableFuture<HttpResponse<String>> sendWithRetry(HttpRequest request) {
return sendWithRetry(request, 0);
}
private CompletableFuture<HttpResponse<String>> sendWithRetry(HttpRequest request, int attempt) {
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.exceptionallyCompose(e -> {
if (attempt < maxRetries) {
System.out.println("Tentativa " + (attempt + 1) + " falhou, tentando novamente...");
try {
Thread.sleep(retryDelayMs * (attempt + 1)); // Backoff exponencial
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
return CompletableFuture.failedFuture(ie);
}
return sendWithRetry(request, attempt + 1);
}
return CompletableFuture.failedFuture(e);
});
}
public void shutdown() {
executor.shutdown();
}
public static void main(String[] args) throws Exception {
RobustHttpClient client = new RobustHttpClient(3, 1000);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/delay/5"))
.timeout(Duration.ofSeconds(60))
.GET()
.build();
client.sendWithRetry(request)
.thenAccept(response -> {
System.out.println("Status: " + response.statusCode());
System.out.println("Body: " + response.body());
})
.exceptionally(e -> {
System.err.println("Falha após retries: " + e.getMessage());
return null;
})
.join();
client.shutdown();
}
}
Comparação de clientes HTTP Java
| Característica | Java HttpClient | OkHttp | Apache HttpClient | Jsoup (fetch) |
|---|---|---|---|---|
| Versão Java mínima | 11+ | Java 8+ | Java 8+ | Java 8+ |
| HTTP/2 | Sim | Sim | Limitado | Não |
| Async/Reactive | CompletableFuture | Callback | Callback | Não |
| Connection Pool | Automático | Configurável | Configurável | Não |
| Proxy Auth | Authenticator | proxyAuthenticator | CredentialsProvider | Header manual |
| Dependências | Nenhuma (JDK) | okhttp.jar | httpclient.jar | jsoup.jar |
| Ideal para | Projetos modernos | Android/Backend | Sistemas legados | Scraping simples |
Principais pontos
- Java HttpClient (11+) é a escolha moderna — usa
ProxySelectoreAuthenticatorpara proxies autenticados. - OkHttp oferece API mais intuitiva com
proxy()eproxyAuthenticator(), ideal para Android e backends. - Jsoup suporta proxies diretamente, mas para scraping robusto combine com OkHttp.
- Apache HttpClient ainda é usado em sistemas legados — configuração mais verbosa.
- Geo-targeting é feito via username:
user-country-US,user-country-DE-city-berlin. - Sessões sticky mantêm o mesmo IP:
user-session-abc123. - TLS customizado via
SSLContextpara sites com certificados não-padronizados. - Retry com backoff é essencial para scraping resiliente.
Conclusão
Configurar proxies HTTP em Java requer atenção à API específica de cada cliente. O java.net.http.HttpClient nativo é suficiente para a maioria dos casos modernos, enquanto OkHttp oferece mais flexibilidade para Android e ambientes corporativos. Para scraping de HTML, Jsoup é indispensável — mas combine-o com um cliente HTTP robusto para controle de conexões e retries.
Proxies residenciais como os oferecidos pela ProxyHat permitem distribuir requisições entre milhares de IPs reais, evitando rate limits e bloqueios. Configure sessões sticky quando precisar manter consistência, ou use rotação automática para máxima dispersão.
Para mais exemplos de uso, consulte nossa documentação em /pt/use-cases/web-scraping ou confira os locais disponíveis para geo-targeting.






