Использование HTTP Proxy в Java: полное руководство с примерами кода

Практическое руководство по работе с HTTP-прокси в Java 17+. Разбираем java.net.http.HttpClient, OkHttp, Jsoup, Apache HttpClient, пул соединений, параллельный скрейпинг и TLS-особенности.

Использование HTTP Proxy в Java: полное руководство с примерами кода

Java-разработчики часто сталкиваются с задачей маршрутизации HTTP-запросов через прокси-серверы. Это может быть веб-скрейпинг, интеграция с API, требующими определённой геолокации, или корпоративные ограничения сети. В этом руководстве мы рассмотрим все популярные HTTP-клиенты в экосистеме Java и покажем, как правильно настроить работу с прокси.

Java 11+ HttpClient: ProxySelector и Authenticator

Модуль java.net.http появился в Java 11 и стал стандартом для новых проектов. Он поддерживает HTTP/2, WebSocket и асинхронные запросы. Для настройки прокси используются ProxySelector и Authenticator.

Базовая настройка прокси

import java.net.InetSocketAddress;
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.time.Duration;

public class JavaHttpClientProxyExample {
    
    public static void main(String[] args) throws Exception {
        // Создаём ProxySelector для HTTP-прокси
        ProxySelector proxySelector = ProxySelector.of(
            new InetSocketAddress("gate.proxyhat.com", 8080)
        );
        
        // Строим клиент с прокси и таймаутами
        HttpClient client = HttpClient.newBuilder()
            .proxy(proxySelector)
            .connectTimeout(Duration.ofSeconds(30))
            .followRedirects(HttpClient.Redirect.NORMAL)
            .build();
        
        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("Status: " + response.statusCode());
        System.out.println("Body: " + response.body());
    }
}

Аутентификация на прокси

Residential-прокси обычно требуют авторизацию. В Java HttpClient используется Authenticator:

import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
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.time.Duration;

public class AuthenticatedProxyExample {
    
    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 = "your_password";
    
    public static void main(String[] args) throws Exception {
        // Authenticator для прокси-авторизации
        Authenticator proxyAuth = 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)
        );
        
        HttpClient client = HttpClient.newBuilder()
            .proxy(proxySelector)
            .authenticator(proxyAuth)
            .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(response.body());
    }
}

Асинхронные запросы через прокси

Для высокопроизводительных приложений используйте асинхронный API:

import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
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;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

public class AsyncProxyExample {
    
    private static final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) {
        Authenticator proxyAuth = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                    "user-country-DE", 
                    "your_password".toCharArray()
                );
            }
        };
        
        HttpClient client = HttpClient.newBuilder()
            .proxy(ProxySelector.of(new InetSocketAddress("gate.proxyhat.com", 8080)))
            .authenticator(proxyAuth)
            .executor(executor)
            .build();
        
        List<String> urls = List.of(
            "https://httpbin.org/ip",
            "https://httpbin.org/headers",
            "https://httpbin.org/user-agent"
        );
        
        List<CompletableFuture<HttpResponse<String>>> futures = urls.stream()
            .map(url -> {
                HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .GET()
                    .build();
                return client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
            })
            .collect(Collectors.toList());
        
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenRun(() -> {
                futures.forEach(f -> {
                    try {
                        HttpResponse<String> response = f.get();
                        System.out.println(response.uri() + " -> " + response.statusCode());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            })
            .join();
        
        executor.shutdown();
    }
}

OkHttp: Proxy и Authenticator

OkHttp от Square — один из самых популярных HTTP-клиентов для Android и серверных Java-приложений. Он предлагает продвинутые возможности: пул соединений, прозрачное сжатие GZIP, кэширование ответов и автоматический retry.

Базовая конфигурация с прокси

import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.time.Duration;

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 = "your_password";
    
    public static void main(String[] args) throws IOException {
        // Создаём объект Proxy
        Proxy proxy = new Proxy(
            Proxy.Type.HTTP,
            new InetSocketAddress(PROXY_HOST, PROXY_PORT)
        );
        
        // Authenticator для прокси-авторизации
        Authenticator proxyAuthenticator = new Authenticator() {
            @Override
            public Request authenticate(Route route, Response response) throws IOException {
                // Предотвращаем бесконечный цикл при неверных креденшалах
                if (response.responseCount() >= 3) {
                    return null;
                }
                String credential = Credentials.basic(USERNAME, PASSWORD);
                return response.request().newBuilder()
                    .header("Proxy-Authorization", credential)
                    .build();
            }
        };
        
        OkHttpClient client = new OkHttpClient.Builder()
            .proxy(proxy)
            .proxyAuthenticator(proxyAuthenticator)
            .connectTimeout(Duration.ofSeconds(30))
            .readTimeout(Duration.ofSeconds(60))
            .writeTimeout(Duration.ofSeconds(60))
            .retryOnConnectionFailure(true)
            .build();
        
        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());
        }
    }
}

Connection Pool и оптимизация

OkHttp автоматически управляет пулом соединений. Для максимальной производительности настройте параметры под вашу нагрузку:

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.util.concurrent.TimeUnit;

public class OptimizedOkHttpClient {
    
    public static OkHttpClient createOptimizedClient() {
        // ConnectionPool: max 100 idle connections, keep-alive 5 минут
        ConnectionPool connectionPool = new ConnectionPool(100, 5, TimeUnit.MINUTES);
        
        return new OkHttpClient.Builder()
            .proxy(new Proxy(
                Proxy.Type.HTTP,
                new InetSocketAddress("gate.proxyhat.com", 8080)
            ))
            .proxyAuthenticator((route, response) -> {
                String credential = Credentials.basic("user-country-US", "your_password");
                return response.request().newBuilder()
                    .header("Proxy-Authorization", credential)
                    .build();
            })
            .connectionPool(connectionPool)
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .writeTimeout(60, TimeUnit.SECONDS)
            // Интервал для проверки живости соединения
            .pingInterval(30, TimeUnit.SECONDS)
            // Retry при ошибках сети
            .retryOnConnectionFailure(true)
            .build();
    }
}

Jsoup: HTML-парсинг через прокси

Jsoup — библиотека для парсинга HTML, которая упрощает извлечение данных со веб-страниц. По умолчанию Jsoup использует HttpURLConnection, но его можно настроить на работу через прокси.

Jsoup с системным прокси

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.net.Authenticator;
import java.net.PasswordAuthentication;

public class JsoupSystemProxyExample {
    
    public static void main(String[] args) throws Exception {
        // Устанавливаем системные свойства для прокси
        System.setProperty("http.proxyHost", "gate.proxyhat.com");
        System.setProperty("http.proxyPort", "8080");
        System.setProperty("https.proxyHost", "gate.proxyhat.com");
        System.setProperty("https.proxyPort", "8080");
        
        // Authenticator для авторизации на прокси
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                    "user-country-US",
                    "your_password".toCharArray()
                );
            }
        });
        
        Document doc = Jsoup.connect("https://example.com")
            .timeout(30000)
            .followRedirects(true)
            .get();
        
        String title = doc.title();
        System.out.println("Page title: " + title);
        
        // Извлекаем все ссылки
        doc.select("a[href]").forEach(link -> {
            System.out.println(link.attr("href") + " -> " + link.text());
        });
    }
}

Jsoup с OkHttp как backend

Для production-решений лучше использовать OkHttp как HTTP-backend для Jsoup. Это даёт контроль над пулом соединений, retry-политикой и таймаутами:

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.net.InetSocketAddress;
import java.net.Proxy;

public class JsoupOkHttpIntegration {
    
    private final OkHttpClient httpClient;
    
    public JsoupOkHttpIntegration(String proxyUser, String proxyPass) {
        Proxy proxy = new Proxy(
            Proxy.Type.HTTP,
            new InetSocketAddress("gate.proxyhat.com", 8080)
        );
        
        this.httpClient = new OkHttpClient.Builder()
            .proxy(proxy)
            .proxyAuthenticator((route, response) -> {
                String credential = okhttp3.Credentials.basic(proxyUser, proxyPass);
                return response.request().newBuilder()
                    .header("Proxy-Authorization", credential)
                    .build();
            })
            .build();
    }
    
    public Document fetchAndParse(String url) throws Exception {
        Request request = new Request.Builder()
            .url(url)
            .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new RuntimeException("HTTP " + response.code() + ": " + response.message());
            }
            
            String html = response.body().string();
            return Jsoup.parse(html, url);
        }
    }
    
    public static void main(String[] args) throws Exception {
        JsoupOkHttpIntegration scraper = new JsoupOkHttpIntegration(
            "user-country-DE",
            "your_password"
        );
        
        Document doc = scraper.fetchAndParse("https://news.ycombinator.com");
        
        doc.select(".titleline > a").forEach(link -> {
            System.out.println(link.text() + " -> " + link.attr("href"));
        });
    }
}

Apache HttpClient: краткий обзор

Apache HttpClient (особенно версия 4.x) всё ещё широко используется в enterprise-проектах. Для настройки прокси требуется HttpHost и CredentialsProvider:

import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
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.impl.conn.PoolingHttpClientConnectionManager;

import java.net.Authenticator;

public class ApacheHttpClientProxyExample {
    
    public static void main(String[] args) throws Exception {
        // Connection Pool
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(200);
        cm.setDefaultMaxPerRoute(50);
        
        // Прокси-хост
        HttpHost proxy = new HttpHost("gate.proxyhat.com", 8080);
        
        // Credentials для авторизации
        BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
            new org.apache.http.auth.AuthScope(proxy),
            new org.apache.http.auth.UsernamePasswordCredentials(
                "user-country-US", 
                "your_password"
            )
        );
        
        // RequestConfig с прокси
        RequestConfig config = RequestConfig.custom()
            .setProxy(proxy)
            .setConnectTimeout(30000)
            .setSocketTimeout(60000)
            .build();
        
        try (CloseableHttpClient client = HttpClients.custom()
            .setConnectionManager(cm)
            .setDefaultCredentialsProvider(credsProvider)
            .setDefaultRequestConfig(config)
            .build()) {
            
            HttpGet request = new HttpGet("https://httpbin.org/ip");
            
            try (CloseableHttpResponse response = client.execute(request)) {
                System.out.println("Status: " + response.getStatusLine());
                
                String body = new String(
                    response.getEntity().getContent().readAllBytes()
                );
                System.out.println("Body: " + body);
            }
        }
    }
}

Параллельный скрейпинг с пулом residential-прокси

Для массового сбора данных необходимо распараллелить запросы и использовать ротацию IP. Residential-прокси идеально подходят для этой задачи, так как они выглядят как обычные пользователи.

import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
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.time.Duration;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class ParallelScraper {
    
    private static final String PROXY_HOST = "gate.proxyhat.com";
    private static final int PROXY_PORT = 8080;
    private static final String BASE_USER = "user";
    private static final String PASSWORD = "your_password";
    
    // Список стран для ротации
    private static final List<String> COUNTRIES = List.of(
        "US", "DE", "GB", "FR", "JP", "AU", "CA", "BR"
    );
    
    private final ExecutorService executor;
    private final HttpClient sharedClient;
    private final AtomicInteger counter = new AtomicInteger(0);
    
    public ParallelScraper(int threadCount) {
        this.executor = Executors.newFixedThreadPool(threadCount);
        
        // Базовый клиент без аутентификации (добавим per-request)
        this.sharedClient = HttpClient.newBuilder()
            .proxy(ProxySelector.of(new InetSocketAddress(PROXY_HOST, PROXY_PORT)))
            .connectTimeout(Duration.ofSeconds(30))
            .executor(executor)
            .build();
    }
    
    private Authenticator createAuthenticator(String country) {
        String username = BASE_USER + "-country-" + country;
        
        return new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, PASSWORD.toCharArray());
            }
        };
    }
    
    public CompletableFuture<ScrapeResult> scrape(String url, String country) {
        long startTime = System.currentTimeMillis();
        int requestId = counter.incrementAndGet();
        
        // Создаём клиент с аутентификацией для конкретной страны
        HttpClient client = HttpClient.newBuilder()
            .proxy(ProxySelector.of(new InetSocketAddress(PROXY_HOST, PROXY_PORT)))
            .authenticator(createAuthenticator(country))
            .connectTimeout(Duration.ofSeconds(30))
            .executor(executor)
            .build();
        
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .timeout(Duration.ofSeconds(60))
            .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
            .GET()
            .build();
        
        return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
            .thenApply(response -> {
                long duration = System.currentTimeMillis() - startTime;
                return new ScrapeResult(
                    requestId,
                    url,
                    country,
                    response.statusCode(),
                    response.body(),
                    duration
                );
            })
            .exceptionally(e -> {
                long duration = System.currentTimeMillis() - startTime;
                return new ScrapeResult(
                    requestId,
                    url,
                    country,
                    -1,
                    "Error: " + e.getMessage(),
                    duration
                );
            });
    }
    
    public void scrapeAll(List<String> urls) throws Exception {
        List<CompletableFuture<ScrapeResult>> futures = new java.util.ArrayList<>();
        
        for (int i = 0; i < urls.size(); i++) {
            String url = urls.get(i);
            String country = COUNTRIES.get(i % COUNTRIES.size());
            
            // Добавляем задержку для избежания rate limiting
            Thread.sleep(100);
            
            futures.add(scrape(url, country));
        }
        
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .join();
        
        // Выводим результаты
        futures.forEach(f -> {
            try {
                ScrapeResult result = f.get();
                System.out.printf(
                    "[%d] %s (%s) -> %d (%dms)%n",
                    result.requestId(),
                    result.url(),
                    result.country(),
                    result.statusCode(),
                    result.duration()
                );
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        
        executor.shutdown();
    }
    
    public record ScrapeResult(
        int requestId,
        String url,
        String country,
        int statusCode,
        String body,
        long duration
    ) {}
    
    public static void main(String[] args) throws Exception {
        ParallelScraper scraper = new ParallelScraper(10);
        
        List<String> urls = List.of(
            "https://httpbin.org/ip",
            "https://httpbin.org/headers",
            "https://httpbin.org/user-agent",
            "https://httpbin.org/ip",
            "https://httpbin.org/headers"
        );
        
        scraper.scrapeAll(urls);
    }
}

TLS и кастомный SSLContext

При работе с прокси могут возникать TLS-особенности. Некоторые прокси используют собственные сертификаты для инспекции трафика (MITM). В таких случаях может потребоваться кастомный SSLContext.

Пропуск верификации сертификата (только для разработки!)

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.net.http.HttpClient;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

public class InsecureTlsExample {
    
    // ВНИМАНИЕ: Используйте только для тестирования!
    // В production это создаёт уязвимость безопасности.
    
    public static HttpClient createInsecureClient() throws Exception {
        // TrustManager, который принимает все сертификаты
        TrustManager[] trustAllCerts = new 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("TLS");
        sslContext.init(null, trustAllCerts, new SecureRandom());
        
        return HttpClient.newBuilder()
            .sslContext(sslContext)
            .proxy(ProxySelector.of(new InetSocketAddress("gate.proxyhat.com", 8080)))
            .build();
    }
}

Правильный подход: кастомный TrustStore

Для production лучше добавить сертификат прокси в custom TrustStore:

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.net.http.HttpClient;
import java.security.KeyStore;
import java.security.SecureRandom;

public class CustomTrustStoreExample {
    
    public static HttpClient createClientWithCustomTrustStore(
        String trustStorePath,
        String trustStorePassword
    ) throws Exception {
        
        // Загружаем кастомный TrustStore
        KeyStore trustStore = KeyStore.getInstance("JKS");
        try (FileInputStream fis = new FileInputStream(trustStorePath)) {
            trustStore.load(fis, trustStorePassword.toCharArray());
        }
        
        // Создаём TrustManagerFactory
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm()
        );
        tmf.init(trustStore);
        
        // Создаём SSLContext
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
        
        return HttpClient.newBuilder()
            .sslContext(sslContext)
            .proxy(ProxySelector.of(new InetSocketAddress("gate.proxyhat.com", 8080)))
            .connectTimeout(java.time.Duration.ofSeconds(30))
            .build();
    }
}

Сравнение HTTP-клиентов для работы с прокси

Критерий Java 11+ HttpClient OkHttp Apache HttpClient 4 Jsoup (нативный)
Поддержка HTTP/2 Да Да Нет (только HTTP/1.1) Нет
Асинхронный API Да (CompletableFuture) Да (через enqueue) Нет (блокирующий) Нет
Настройка прокси ProxySelector + Authenticator Proxy + Authenticator HttpHost + CredentialsProvider Системные свойства
Connection Pool Встроенный Встроенный (ConnectionPool) PoolingHttpClientConnectionManager Нет
Retry-политика Ручная реализация Встроенная Через HttpRequestRetryHandler Нет
Требует внешних зависимостей Нет (JDK) Да Да Да (только Jsoup)
Идеален для Новые проекты, JDK-only Android, production Legacy системы Простой парсинг

Best Practices для production

  • Всегда устанавливайте таймауты — connect timeout, read timeout, write timeout. Без них приложение может зависнуть бесконечно.
  • Используйте connection pooling — переиспользование TCP-соединений значительно ускоряет работу при множественных запросах.
  • Реализуйте exponential backoff для retry — при ошибках сети не пытайтесь переподключиться мгновенно.
  • Логируйте все ошибки — включайте URL, статус-код, время ответа и страну/сессию прокси.
  • Ротируйте сессии прокси — для大规模 скрейпинга используйте параметр -session-XXX в username для sticky sessions.
  • Уважайте robots.txt и ToS — проверяйте, разрешён ли скрейпинг на целевом сайте.

Совет: Для residential-прокси используйте формат username user-country-US-session-abc123. Это создаст «липкую» сессию — все запросы в рамках сессии будут идти с одного IP, что важно для авторизованных сессий и корзин покупок.

Key Takeaways

  • Java 11+ HttpClient — нативное решение без зависимостей, подходит для новых проектов. Используйте ProxySelector.of() и Authenticator для аутентификации.
  • OkHttp — лучший выбор для production: встроенный connection pool, retry-механизмы, отличная производительность. Настройте Proxy и proxyAuthenticator.
  • Jsoup удобен для HTML-парсинга, но для HTTP-запросов лучше интегрировать его с OkHttp для контроля над соединениями.
  • Всегда настраивайте таймауты и connection pooling — это критично для производительности.
  • Для параллельного скрейпинга используйте CompletableFuture или ExecutorService с ротацией стран/сессий прокси.
  • TLS-особенности прокси решаются через кастомный SSLContext или TrustStore.

Готовы начать работу с прокси? Зарегистрируйтесь на ProxyHat и получите доступ к residential, mobile и datacenter-прокси в более чем 190 странах. Подробную документацию по API и примеры кода на Java вы найдёте в нашем разделе блога.

Готовы начать?

Доступ к более чем 50 млн резидентных IP в 148+ странах с AI-фильтрацией.

Смотреть ценыРезидентные прокси
← Вернуться в Блог