Что такое HttpClient и как правильно с ним работать?

HttpClient — это класс из пространства имён System.Net.Http в .NET, предназначенный для отправки HTTP-запросов и получения HTTP-ответов от ресурса, идентифицируемого URI. Это основной инструмент для взаимодействия с внешними веб-сервисами и REST API в приложениях Xamarin и Xamarin.Forms. Он позволяет выполнять GET, POST, PUT, DELETE и другие запросы, отправлять данные, загружать файлы, а также управлять заголовками и куки.

Основные особенности HttpClient

  • Поддерживает асинхронное выполнение запросов через async/await.

  • Позволяет повторно использовать соединения, если используется правильно.

  • Имеет поддержку тайм-аутов, заголовков, аутентификации и проксирования.

  • Является кроссплатформенным — работает на Android, iOS, Windows и других платформах.

Создание экземпляра HttpClient

HttpClient httpClient = new HttpClient();

Чтобы задать базовый адрес:

httpClient.BaseAddress = new Uri("https://api.example.com/");

Выполнение HTTP-запросов

GET-запрос:

var response = await httpClient.GetAsync("users/1");

POST-запрос:

var json = JsonConvert.SerializeObject(newUser);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync("users", content);

PUT-запрос:

var json = JsonConvert.SerializeObject(updatedUser);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PutAsync("users/1", content);

DELETE-запрос:

var response = await httpClient.DeleteAsync("users/1");

Чтение ответа

if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var user = JsonConvert.DeserializeObject<User>(responseContent);
}
else
{
Debug.WriteLine($"Ошибка: {response.StatusCode}");
}

Добавление заголовков

httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "your_token");
httpClient.DefaultRequestHeaders.Add("Custom-Header", "value");

Обработка ошибок

try
{
var response = await httpClient.GetAsync("users");
response.EnsureSuccessStatusCode(); // выбрасывает исключение, если код != 2xx
var json = await response.Content.ReadAsStringAsync();
var users = JsonConvert.DeserializeObject&lt;List<User&gt;>(json);
}
catch (HttpRequestException ex)
{
Debug.WriteLine($"Ошибка HTTP: {ex.Message}");
}
catch (Exception ex)
{
Debug.WriteLine($"Общая ошибка: {ex.Message}");
}

Тайм-аут запроса

httpClient.Timeout = TimeSpan.FromSeconds(30);

Можно также использовать CancellationToken:

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var response = await httpClient.GetAsync("users", cts.Token);

Переиспользование HttpClient

Очень важно не создавать новый HttpClient при каждом запросе. Это может привести к исчерпанию сокетов и утечкам памяти. Рекомендуется:

  • Использовать Singleton-паттерн

  • Или внедрять через **Dependency Injection
    **

  • Или использовать HttpClientFactory (в MAUI/.NET Core)

Пример Singleton:

public static class HttpClientProvider
{
private static HttpClient \_client;
public static HttpClient Client => \_client ??= CreateClient();
private static HttpClient CreateClient()
{
var client = new HttpClient();
client.BaseAddress = new Uri("https://api.example.com/");
return client;
}
}

Использование:

var response = await HttpClientProvider.Client.GetAsync("users");

HttpMessageHandler и делегаты

Можно использовать делегирующие обработчики для логирования, подмены заголовков, ретраев:

public class LoggingHandler : DelegatingHandler
{
public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
protected override async Task&lt;HttpResponseMessage&gt; SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine($"Запрос: {request.Method} {request.RequestUri}");
var response = await base.SendAsync(request, cancellationToken);
Debug.WriteLine($"Ответ: {response.StatusCode}");
return response;
}
}

Подключение:

var client = new HttpClient(new LoggingHandler(new HttpClientHandler()));

Отправка форм (multipart/form-data)

Для загрузки файлов или форм:

var form = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(fileBytes);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
form.Add(fileContent, "file", "photo.jpg");
form.Add(new StringContent("myuser"), "username");
var response = await httpClient.PostAsync("upload", form);

Работа с куками

HttpClient сам по себе не сохраняет куки. Для этого используйте HttpClientHandler с включённой поддержкой CookieContainer:

var cookieContainer = new CookieContainer();
var handler = new HttpClientHandler { CookieContainer = cookieContainer };
var client = new HttpClient(handler);

Использование System.Text.Json вместо Newtonsoft

var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var user = JsonSerializer.Deserialize&lt;User&gt;(jsonString, options);

Отладка и логирование

  • Используйте Fiddler, Charles Proxy, Wireshark или встроенные обработчики (HttpMessageHandler) для анализа трафика.

  • Debug.WriteLine(response.RequestMessage.ToString()) позволяет видеть отправляемые заголовки.

Сетевые ограничения на мобильных устройствах

Убедитесь, что в AndroidManifest.xml добавлены разрешения:

```python
<uses-permission android:name="android.permission.INTERNET" />

На iOS начиная с iOS 9 нужно разрешить небезопасные соединения (HTTP) в Info.plist, если используется не HTTPS:  
<br/>```python  
&lt;key&gt;NSAppTransportSecurity&lt;/key&gt;
&lt;dict&gt;
&lt;key&gt;NSAllowsArbitraryLoads&lt;/key&gt;
&lt;true/&gt;
&lt;/dict&gt;  

Распространённые ошибки

Ошибка Причина
TaskCanceledException Тайм-аут запроса или CancellationToken отменил запрос
--- ---
HttpRequestException Сетевая ошибка или неправильный адрес
--- ---
SocketException: No such host is known DNS-ошибка, нет интернета или опечатка в URI
--- ---
500 Internal Server Error Проблема на сервере API
--- ---

HttpClient — мощный инструмент, но его правильное использование требует понимания принципов работы HTTP, управления временем жизни объекта, обработки ошибок и асинхронного программирования. В Xamarin этот класс широко используется для создания REST-клиентов, авторизации, загрузки медиа, синхронизации данных и других задач.