Налаштування проксі для HTTP-запитів у C# за допомогою HttpClient передбачає створення екземпляра HttpClientHandler, присвоєння об'єкта WebProxy з адресою проксі та необов'язковими обліковими даними його властивості Proxy, а потім передачу цього налаштованого обробника до конструктора HttpClient. Це налаштування дозволяє програмам маршрутизувати вихідний веб-трафік через проміжний сервер, що є важливим для мережевої безпеки, контролю доступу, ведення журналів або обходу географічних обмежень.
Розуміння HttpClient, HttpClientHandler та WebProxy
HttpClient — це основний клас у .NET для надсилання HTTP-запитів та отримання HTTP-відповідей. Він розроблений для довготривалих екземплярів та одночасних запитів.
HttpClientHandler — це базовий обробник повідомлень, який HttpClient використовує для надсилання запитів. Він надає параметри конфігурації для мережевих налаштувань, включаючи конфігурацію проксі, облікові дані та налаштування SSL/TLS.
WebProxy — це клас, який вказує URI проксі-сервера та дозволяє налаштовувати списки обходу проксі та облікові дані.
Управління екземплярами HttpClient
Екземпляри HttpClient зазвичай слід повторно використовувати для кількох запитів, щоб уникнути проблем з вичерпанням сокетів. Створення нового HttpClient для кожного запиту може призвести до проблем з продуктивністю та виснаження ресурсів. Поширеним шаблоном є використання одного екземпляра HttpClient протягом усього життєвого циклу програми або використання IHttpClientFactory у програмах ASP.NET Core.
Базова конфігурація проксі
Щоб налаштувати базовий HTTP або HTTPS проксі, створіть екземпляр HttpClientHandler, встановіть його властивість Proxy на новий об'єкт WebProxy, ініціалізований URI проксі, а потім передайте цей обробник до конструктора HttpClient.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class ProxySetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.proxy.server:8080"; // Замініть на адресу вашого проксі
string targetUrl = "http://httpbin.org/get"; // Публічна кінцева точка для тестування
// Створіть екземпляр WebProxy
var webProxy = new WebProxy(proxyAddress, BypassOnLocal: false);
// Створіть HttpClientHandler та призначте WebProxy
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true // Явно увімкніть використання проксі
};
// Створіть HttpClient з налаштованим обробником
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode(); // Генерує виняток, якщо HTTP-статус-код є помилкою
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Запит успішний. Фрагмент відповіді:");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500))); // Вивести перші 500 символів
}
catch (HttpRequestException e)
{
Console.WriteLine($"Помилка запиту: {e.Message}");
}
catch (WebException e)
{
Console.WriteLine($"Помилка проксі або мережі: {e.Message}");
}
}
}
}
У цьому прикладі:
* WebProxy(proxyAddress, BypassOnLocal: false) створює об'єкт проксі. BypassOnLocal: false гарантує, що запити до локальних адрес (наприклад, localhost) також проходять через проксі, якщо їх явно не обійти пізніше.
* handler.UseProxy = true явно вказує обробнику використовувати налаштований проксі.
Проксі з автентифікацією
Якщо проксі-сервер вимагає автентифікації (наприклад, ім'я користувача та пароль), встановіть властивість Credentials об'єкта WebProxy за допомогою екземпляра NetworkCredential.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class AuthenticatedProxySetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.authenticated.proxy.server:8080"; // Замініть
string proxyUsername = "your_username"; // Замініть
string proxyPassword = "your_password"; // Замініть
string targetUrl = "http://httpbin.org/get";
var credentials = new NetworkCredential(proxyUsername, proxyPassword);
var webProxy = new WebProxy(proxyAddress, BypassOnLocal: false)
{
Credentials = credentials
};
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true
};
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Запит успішний з автентифікованим проксі.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Помилка запиту: {e.Message}");
}
catch (WebException e)
{
Console.WriteLine($"Помилка проксі або мережі: {e.Message}");
}
}
}
}
Використання системного проксі за замовчуванням
HttpClientHandler можна налаштувати на використання системних налаштувань проксі за замовчуванням, які зазвичай налаштовуються в операційній системі або налаштуваннях Internet Explorer. Це часто бажана поведінка в корпоративних середовищах.
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class SystemDefaultProxySetup
{
public static async Task Main(string[] args)
{
string targetUrl = "http://httpbin.org/get";
var handler = new HttpClientHandler
{
UseSystemProxy = true // Використовувати системні налаштування проксі за замовчуванням
};
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Запит успішний з використанням системного проксі за замовчуванням.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Помилка запиту: {e.Message}");
}
catch (Exception e)
{
Console.WriteLine($"Помилка: {e.Message}");
}
}
}
}
Встановлення UseSystemProxy = true автоматично налаштовує HttpClientHandler на виявлення та використання налаштувань проксі, визначених на рівні операційної системи. Якщо UseSystemProxy є true, властивість Proxy ігнорується.
Обхід проксі для конкретних адрес
Клас WebProxy надає механізми для обходу проксі для певних адрес.
BypassProxyOnLocal
Встановлення BypassProxyOnLocal = true у конструкторі або властивості WebProxy вкаже проксі не використовуватись для локальних ресурсів інтранету. Це часто бажано, щоб запобігти непотрібній маршрутизації внутрішнього трафіку через зовнішній проксі.
var webProxy = new WebProxy("http://your.proxy.server:8080")
{
BypassProxyOnLocal = true // Не використовувати проксі для локальних адрес
};
BypassList
Для більш детального контролю властивість BypassList дозволяє вказати масив регулярних виразів, які визначають URI, для яких проксі слід обійти.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class ProxyBypassListSetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.proxy.server:8080";
string targetUrl = "http://internal.api.com/data"; // Приклад внутрішнього URL
string externalUrl = "http://external.api.com/data"; // Приклад зовнішнього URL
// Визначте список обходу за допомогою регулярних виразів
string[] bypassList = new string[]
{
"internal\\.api\\.com", // Обхід для internal.api.com
"\\.local$" // Обхід для будь-якого хоста, що закінчується на .local
};
var webProxy = new WebProxy(proxyAddress)
{
BypassList = bypassList,
BypassProxyOnLocal = false // Явно обробляти локальний обхід через BypassList, якщо потрібно
};
var handler = new HttpClientHandler
{
Proxy = webProxy,
UseProxy = true
};
using (var httpClient = new HttpClient(handler))
{
Console.WriteLine($"Спроба запиту до {targetUrl} (має обійти проксі)...");
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
Console.WriteLine($"Запит до {targetUrl} успішний. (Перевірте логи проксі, якщо доступні)");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Помилка запиту до {targetUrl}: {e.Message}");
}
Console.WriteLine($"\nСпроба запиту до {externalUrl} (має використовувати проксі)...");
try
{
HttpResponseMessage response = await httpClient.GetAsync(externalUrl);
response.EnsureSuccessStatusCode();
Console.WriteLine($"Запит до {externalUrl} успішний. (Перевірте логи проксі, якщо доступні)");
}
catch (HttpRequestException e)
{
Console.WriteLine($"Помилка запиту до {externalUrl}: {e.Message}");
}
}
}
}
HttpClientHandler проти SocketsHttpHandler
.NET Core 2.1 представив SocketsHttpHandler як обробник за замовчуванням для HttpClient, що пропонує покращену продуктивність та кросплатформну узгодженість. HttpClientHandler все ще існує і може бути явно використаний, але SocketsHttpHandler зазвичай є кращим для нової розробки. При використанні SocketsHttpHandler конфігурація проксі дещо відрізняється.
| Функція | HttpClientHandler |
SocketsHttpHandler (Рекомендовано для .NET Core/.NET 5+) |
|---|---|---|
| Тип проксі | WebProxy |
IWebProxy (часто WebProxy або власна реалізація) |
| Конфігурація | Встановіть властивість Proxy з екземпляром WebProxy. |
Встановіть властивість Proxy з екземпляром IWebProxy. |
| Системний проксі | UseSystemProxy = true |
UseProxy = true та Proxy = WebRequest.DefaultWebProxy або null для системного за замовчуванням. |
| Автентифікація | WebProxy.Credentials |
WebProxy.Credentials (якщо використовується WebProxy) |
| SOCKS Проксі | Безпосередньо не підтримується. | Пряма підтримка SOCKS5 через властивість Proxy, встановлену на new WebProxy("socks5://...") |
| За замовчуванням у .NET | За замовчуванням для .NET Framework. | За замовчуванням для .NET Core 2.1+ / .NET 5+. |
Налаштування проксі за допомогою SocketsHttpHandler
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class SocketsHttpHandlerProxySetup
{
public static async Task Main(string[] args)
{
string proxyAddress = "http://your.proxy.server:8080";
string targetUrl = "http://httpbin.org/get";
var webProxy = new WebProxy(proxyAddress);
// SocketsHttpHandler є стандартним у сучасному .NET, але може бути явно використаний
var handler = new SocketsHttpHandler
{
Proxy = webProxy, // Призначити екземпляр IWebProxy
UseProxy = true, // Явно увімкнути використання проксі
AllowAutoRedirect = true, // Приклад інших властивостей SocketsHttpHandler
PooledConnectionLifetime = TimeSpan.FromMinutes(5)
};
using (var httpClient = new HttpClient(handler))
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(targetUrl);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Запит успішний з використанням SocketsHttpHandler.");
Console.WriteLine(responseBody.Substring(0, Math.Min(responseBody.Length, 500)));
}
catch (HttpRequestException e)
{
Console.WriteLine($"Помилка запиту: {e.Message}");
}
catch (Exception e)
{
Console.WriteLine($"Помилка: {e.Message}");
}
}
}
}
Для використання системного проксі за замовчуванням з SocketsHttpHandler встановіть UseProxy = true та Proxy = WebRequest.DefaultWebProxy. Якщо Proxy є null і UseProxy є true, SocketsHttpHandler спробує використати системний проксі за замовчуванням.
Обробка помилок та налагодження
При виникненні проблем з конфігурацією проксі, розгляньте наступне:
* Мережеве з'єднання: Переконайтеся, що хост програми може досягти проксі-сервера.
* Статус проксі-сервера: Переконайтеся, що проксі-сервер працює та правильно налаштований.
* Автентифікація: Двічі перевірте облікові дані проксі. Неправильні облікові дані часто призводять до помилок HTTP 407 Proxy Authentication Required.
* Правила брандмауера: Перевірте локальні та мережеві правила брандмауера, які можуть блокувати трафік до або від проксі.
* Журнали проксі: Якщо доступні журнали проксі-сервера, перевірте їх на наявність спроб з'єднання та помилок.
* Винятки: Перехоплюйте HttpRequestException та WebException (для HttpClientHandler у .NET Framework) для отримання детальних повідомлень про помилки.
Міркування безпеки
- Довіра: Маршрутизуйте трафік лише через довірені проксі-сервери. Шкідливі проксі можуть перехоплювати, змінювати або реєструвати конфіденційні дані.
- Облікові дані: Зберігайте облікові дані проксі безпечно, уникаючи жорсткого кодування їх безпосередньо у вихідному коді. Використовуйте змінні середовища, файли конфігурації або служби управління секретами.
- SSL/TLS: Переконайтеся, що проксі правильно обробляє трафік SSL/TLS. Якщо проксі виконує SSL-інспекцію (Man-in-the-Middle), програма може вимагати довіри до додаткового кореневого центру сертифікації.
HttpClientHandlerмає властивістьServerCertificateCustomValidationCallbackдля спеціальної перевірки сертифікатів, але її слід використовувати з обережністю.