GeekProxy в Go, PHP, Java и C#
Четыре языка, четыре стандартных HTTP-клиента, один прокси. Каждый раздел ниже самодостаточен: точные имена опций из официальной документации, сниппет, который тянет ipinfo через прокси, и одна ловушка, своя у каждой платформы. У Java ловушка самая противная, так что кусок про Basic поверх CONNECT не пропускайте.
Что нужно: активный план GeekProxy и данные прокси из кабинета. Каждый сниппет запускается меньше чем за минуту, если тулчейн уже стоит.
Получить прокси1 Перед началом
Под капотом все четыре клиента делают одно и то же. Для цели на https:// они открывают CONNECT-туннель через прокси и шлют Proxy-Authorization только в этом CONNECT. Сайт видит IP прокси, остальное на вашей машине не меняется.
- HTTP-прокси с логином и паролем это безопасный выбор в любом из четырёх языков. SOCKS5 с паролем тоже работает во всех четырёх, оговорки в каждом разделе
- Порты GeekProxy это обычные HTTP-прокси. Там, где клиент спрашивает схему самого прокси, это
http, даже для целей наhttps:// - На плане с белым списком IP данные доступа убираем: никакого
LOGIN:PASSWORD@в URL, никакого аутентификатора, никакого объекта с учётными данными - Спецсимволы в пароле внутри URL кодируются процентами. Опции, которые берут логин и пароль отдельными строками, хотят их как есть
Что понадобится
- Активный план GeekProxy (датацентр, ISP или резидентские)
- Данные прокси из кабинета: хост, порт, логин, пароль
- Go с
net/http, PHP 7.3 или новее с расширением curl, JDK 11 или новее, .NET 6 или новее
- Поле Откуда взять
- Протокол HTTP / SOCKS5
- Хост IP или имя шлюза из кабинета
- Порт из кабинета
- Логин из кабинета
- Пароль из кабинета
2 Где взять данные прокси
- Войдите в кабинет GeekProxy
- Откройте план. У планов с оплатой за IP (датацентр, ISP) список адресов, порты, логин и пароль лежат прямо на карточке, а кнопка Export отдаёт весь список текстом
- У резидентских и мобильных планов нажмите Options. Панель Proxy Configuration соберёт строку логина с вашей страной, городом и настройками сессии. Готовую строку копируйте из Proxy List
3 Go
Go самый простой. У http.Transport есть поле Proxy, оно принимает функцию, а http.ProxyURL делает такую функцию из разобранного URL. В описании поля перечислены схемы: http, https, socks5 и socks5h. Если в URL есть userinfo, транспорт сам отправит заголовок Proxy-Authorization.
proxyURL, _ := url.Parse("http://LOGIN:PASSWORD@IP:PORT") // или "socks5://LOGIN:PASSWORD@IP:PORT"
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
}
resp, err := client.Get("https://ipinfo.io/json")
SOCKS5 с паролем: да, встроено, причём socks5 трактуется как socks5h, то есть имя хоста резолвит прокси. Никаких лишних пакетов. Пакет golang.org/x/net/proxy нужен только для сырого TCP: proxy.SOCKS5("tcp", "IP:PORT", &proxy.Auth{User: "LOGIN", Password: "PASSWORD"}, proxy.Direct) даёт dialer для SMTP, базы данных и любого другого сокета.
Можно вообще не трогать код. http.DefaultTransport использует http.ProxyFromEnvironment, который читает HTTPS_PROXY, HTTP_PROXY и NO_PROXY (нижний регистр важнее). Значение может быть полным URL, в том числе SOCKS5, или голым host:port, который считается HTTP. Две особенности из документации: запросы на localhost через прокси из окружения не идут никогда, а в CGI-процессе HTTP_PROXY отвергается намеренно.
4 PHP
Расширение curl отдаёт опции libcurl один в один. CURLOPT_PROXY принимает хост, CURLOPT_PROXYPORT порт, CURLOPT_PROXYUSERPWD данные доступа строкой LOGIN:PASSWORD. CURLOPT_PROXYTYPE по умолчанию CURLPROXY_HTTP; для SOCKS5 с DNS на стороне прокси берите CURLPROXY_SOCKS5_HOSTNAME, а не просто CURLPROXY_SOCKS5, который резолвит имена у вас.
$ch = curl_init('https://ipinfo.io/json');
curl_setopt_array($ch, [
CURLOPT_PROXY => 'IP',
CURLOPT_PROXYPORT => PORT,
CURLOPT_PROXYUSERPWD => 'LOGIN:PASSWORD',
CURLOPT_PROXYTYPE => CURLPROXY_HTTP, // CURLPROXY_SOCKS5_HOSTNAME для SOCKS5
CURLOPT_PROXYAUTH => CURLAUTH_BASIC,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
]);
$body = curl_exec($ch);
SOCKS5 с паролем здесь тоже работает. Данные доступа несёт тот же CURLOPT_PROXYUSERPWD. А вот переключатель метода аутентификации другой: CURLOPT_PROXYAUTH для HTTP-прокси (только Basic или NTLM), CURLOPT_SOCKS5_AUTH для SOCKS5, с PHP 7.3. libcurl принимает в CURLOPT_PROXY и полную строку socks5h://LOGIN:PASSWORD@IP:PORT; мануал PHP документирует там только хост, так что считайте эту форму документированной со стороны libcurl.
Guzzle заворачивает то же самое в опцию запроса proxy. Строка задаёт один прокси на все протоколы, массив задаёт прокси по схемам плюс список no. В документации сказано, что URL может нести схему, имя пользователя и пароль.
$client = new GuzzleHttp\Client(['timeout' => 30]);
$res = $client->request('GET', 'https://ipinfo.io/json', [
'proxy' => [
'http' => 'http://LOGIN:PASSWORD@IP:PORT',
'https' => 'http://LOGIN:PASSWORD@IP:PORT',
'no' => ['localhost'],
],
]);
echo $res->getBody();
5 Java
Java делит задачу надвое. Адрес прокси приходит из системных свойств или объекта Proxy, данные доступа из java.net.Authenticator. Свойства http.proxyUser не существует. Его ищут часами.
Теперь ловушка. С JDK 8u111 файл conf/net.properties поставляется со строкой jdk.http.auth.tunneling.disabledSchemes=Basic. По-русски: JDK отказывается слать Basic-данные в CONNECT, а это любая цель на https:// через HTTP-прокси. Ваш Authenticator даже не спросят, и вы получите 407. Очистите свойство до первого запроса, в коде или через -Djdk.http.auth.tunneling.disabledSchemes="" в командной строке.
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); // разрешить Basic в CONNECT
HttpClient client = HttpClient.newBuilder()
.proxy(ProxySelector.of(new InetSocketAddress("IP", PORT)))
.authenticator(new Authenticator() {
@Override protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("LOGIN", "PASSWORD".toCharArray());
}
})
.build();
HttpResponse<String> r = client.send(
HttpRequest.newBuilder(URI.create("https://ipinfo.io/json")).build(),
HttpResponse.BodyHandlers.ofString());
System.out.println(r.body());
Для всей JVM без кода: -Dhttps.proxyHost=IP -Dhttps.proxyPort=PORT -Dhttp.proxyHost=IP -Dhttp.proxyPort=PORT плюс Authenticator.setDefault(...) где-нибудь на старте. В таком глобальном аутентификаторе проверяйте getRequestorType() == RequestorType.PROXY, чтобы не отдать пароль от прокси какому-нибудь сайту.
SOCKS5 с паролем: да, на уровне сокетов. -DsocksProxyHost=IP -DsocksProxyPort=PORT -Djava.net.socks.username=LOGIN -Djava.net.socks.password=PASSWORD заворачивает каждый java.net.Socket, включая JDBC и SMTP. Сюрприз из документации: если данные доступа не заданы вообще, JDK отправит ваш user.name как имя пользователя SOCKS с пустым паролем. У HttpClient из JDK 11 SOCKS в документированном API нет, там держитесь HTTP.
OkHttp туннелирует сам и держит отдельный proxyAuthenticator. По документации аутентификатор вызывается всегда перед CONNECT с фиктивным 407 и челленджем OkHttp-Preemptive, так что данные уходят с первой попытки. От зацикливания защищает возврат null, когда у запроса уже есть заголовок Proxy-Authorization.
OkHttpClient client = new OkHttpClient.Builder()
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("IP", PORT)))
.proxyAuthenticator((route, response) -> {
if (response.request().header("Proxy-Authorization") != null) {
return null; // сдаёмся, аутентификация уже не прошла
}
String credential = Credentials.basic("LOGIN", "PASSWORD");
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
})
.build();
6 C# и .NET
В .NET прокси это объект WebProxy, который отдают в HttpClientHandler. Данные доступа лежат в его свойстве Credentials как NetworkCredential. Документация отмечает, что прокси на уровне обработчика перекрывает настройки машины и конфига приложения.
var proxy = new WebProxy("http://IP:PORT")
{
Credentials = new NetworkCredential("LOGIN", "PASSWORD"),
BypassProxyOnLocal = true,
};
var handler = new HttpClientHandler { Proxy = proxy, UseProxy = true };
using var client = new HttpClient(handler);
Console.WriteLine(await client.GetStringAsync("https://ipinfo.io/json"));
SOCKS4, SOCKS4a и SOCKS5 появились в .NET 6. Выбираются они схемой в URI. Помните сноску из анонса про .NET 6: конструктор WebProxy(string) там умеет только HTTP, поэтому пишите new WebProxy(new Uri("socks5://IP:PORT")); в .NET 7 это поправили. SOCKS5 с паролем документирован в форме переменной окружения, socks5://LOGIN:PASSWORD@IP:PORT. Уходит ли свойство Credentials в SOCKS5-рукопожатие, документация не говорит. Нужно, берите форму с URL.
Переменные окружения накрывают каждый HttpClient без явного прокси через HttpClient.DefaultProxy. На Linux это единственный источник: нет переменных, нет прокси. Читаются HTTP_PROXY, HTTPS_PROXY, ALL_PROXY и NO_PROXY, сначала в нижнем регистре, и значение может содержать логин и пароль. В NO_PROXY нет масок; точка в начале матчит поддомены.
HTTPS_PROXY="http://LOGIN:PASSWORD@IP:PORT" HTTP_PROXY="http://LOGIN:PASSWORD@IP:PORT" dotnet run
Если прокси закрывает соединение вместо ответа 407, включите предварительную аутентификацию: System.Net.Http.SocketsHttpHandler.ProxyPreAuthenticate в runtimeconfig.json или переменная DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_PROXYPREAUTHENTICATE=1. Тогда Basic-данные уйдут с первым же запросом.
7 Проверка работы
Каждый сниппет выше печатает тело https://ipinfo.io/json. Поле ip должно показать адрес прокси, а не ваш. На ISP или датацентре это адрес из кабинета, на Residential или Turbo любой адрес из пула в выбранной стране. Запустите ещё раз без прокси: другой ip значит, что прокси действительно был на пути.
8 Какой продукт GeekProxy подходит
Большая часть кода на этих четырёх языках это интеграции: API-клиент, бот, чекер на сервере. Им нужен один постоянный адрес без счётчика трафика, то есть статический ISP или датацентр IPv4, в режиме белого списка, если не хочется держать пароль в конфиге. Краулер на Go, PHP, Java или C# это другой случай: Residential Turbo или Residential Flex, ротация для охвата и sticky-логин, когда сессия должна удержать IP. Протокол по умолчанию HTTP. SOCKS5 оправдан, только когда через прокси должен идти не-HTTP протокол, скажем через x/net/proxy в Go или socksProxyHost в Java. Turbo даёт там SOCKS5; Flex выдаёт URL с socks5h и работает только по TCP.
9 Частые проблемы
Java: 407 или «Unable to tunnel through proxy» при верном пароле
Дефолт jdk.http.auth.tunneling.disabledSchemes=Basic. Очистите его до первого запроса или поправьте $JAVA_HOME/conf/net.properties.
PHP: SOCKS5 работает, но сайты с гео-балансировкой ведут себя неправильно
CURLPROXY_SOCKS5 резолвит DNS локально, и сайт выбирается по вашему местоположению. Переключитесь на CURLPROXY_SOCKS5_HOSTNAME.
.NET на Linux игнорирует системный прокси
С точки зрения .NET системного прокси на Linux нет. Задайте переменные окружения или явный WebProxy.
Go: прокси из окружения пропускается для одного хоста
localhost через прокси из окружения не ходит никогда, так задумано. Всё остальное слушается NO_PROXY, проверьте список.
407 везде
Не сходятся логин или пароль, либо план в режиме белого списка, а IP сервера в нём нет. В форме URL пароль кодируется процентами, в отдельных строковых опциях нет.
Прокси для вашего бэкенда
Статические ISP и датацентр для интеграций, ротируемые резидентские для краулеров, HTTP и SOCKS5.
Заказать