HTTP клиент на C#: делаем запросы правильно от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

HTTP клиент на C#: делаем запросы правильно от А до Я

В современной разработке на платформе .NET работа с HTTP-запросами — одна из ключевых задач. Будь то интеграция с внешним REST API, отправка данных на сервер или загрузка веб-страниц — правильное использование HttpClient в C# критически важно для производительности и стабильности приложения. В этой статье мы разберём все аспекты работы с HTTP клиентом на C#: от базовых примеров до продвинутых техник, обработки ошибок и лучших практик.

1. Основы работы с HttpClient в C#

HttpClient — это основной класс в .NET для отправки HTTP-запросов и получения ответов. Он находится в пространстве имён System.Net.Http и доступен начиная с .NET Framework 4.5 и всех версий .NET Core/.NET 5+.

Важное правило: HttpClient предназначен для повторного использования. Создавать новый экземпляр на каждый запрос — антипаттерн, который может привести к исчерпанию сокетов (socket exhaustion). Вместо этого используйте один статический или синглтон-экземпляр.

Базовый пример GET-запроса:

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    private static readonly HttpClient client = new HttpClient();

    static async Task Main(string[] args)
    {
        try
        {
            HttpResponseMessage response = await client.GetAsync("https://api.example.com/data");
            response.EnsureSuccessStatusCode();
            string responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseBody);
        }
        catch (HttpRequestException e)
        {
            Console.WriteLine($"Ошибка запроса: {e.Message}");
        }
    }
}

В этом примере мы создаём статический HttpClient, отправляем GET-запрос, проверяем успешность ответа с помощью EnsureSuccessStatusCode() и читаем тело ответа как строку.

2. Типы HTTP-запросов и работа с заголовками

Помимо GET, HttpClient поддерживает все основные HTTP-методы: POST, PUT, DELETE, PATCH и другие. Рассмотрим отправку POST-запроса с JSON-данными — это наиболее частый сценарий при работе с REST API.

Пример POST-запроса с JSON:

using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    private static readonly HttpClient client = new HttpClient();

    static async Task Main(string[] args)
    {
        var data = new { Name = "John", Age = 30 };
        string json = JsonSerializer.Serialize(data);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        try
        {
            HttpResponseMessage response = await client.PostAsync("https://api.example.com/users", content);
            response.EnsureSuccessStatusCode();
            string result = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Создан пользователь: {result}");
        }
        catch (HttpRequestException e)
        {
            Console.WriteLine($"Ошибка: {e.Message}");
        }
    }
}

Работа с заголовками: Часто API требуют передачи токенов аутентификации или других заголовков. Добавлять их можно двумя способами:

  • Глобально — через свойство DefaultRequestHeaders (для всех запросов клиента).
  • Локально — через коллекцию Headers в объекте HttpRequestMessage (для конкретного запроса).

Пример добавления заголовка Authorization:

// Глобально
client.DefaultRequestHeaders.Authorization = 
    new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "your-token");

// Локально
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/protected");
request.Headers.Add("X-Custom-Header", "value");
var response = await client.SendAsync(request);

3. Обработка ошибок, таймауты и повторные попытки

Реальные приложения должны быть устойчивы к сетевым проблемам. Рассмотрим три ключевых аспекта правильной работы с HTTP клиентом на C#.

3.1. Таймауты

По умолчанию HttpClient имеет таймаут 100 секунд. Это слишком много для большинства сценариев. Устанавливайте разумные таймауты через свойство Timeout:

client.Timeout = TimeSpan.FromSeconds(30); // 30 секунд

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

Не все ошибки — это исключения. HTTP-статусы 4xx и 5xx не вызывают исключений автоматически. Используйте EnsureSuccessStatusCode() или проверяйте IsSuccessStatusCode вручную:

if (response.IsSuccessStatusCode)
{
    // Успех
}
else
{
    Console.WriteLine($"Ошибка: {response.StatusCode}");
    string errorBody = await response.Content.ReadAsStringAsync();
}

3.3. Политика повторных попыток (Retry)

Для временных ошибок (например, 503 Service Unavailable или таймаутов) используйте библиотеку Polly или реализуйте простой retry-механизм:

using Polly;
using Polly.Retry;

private static readonly AsyncRetryPolicy retryPolicy = 
    Policy.Handle<HttpRequestException>()
          .OrResult<HttpResponseMessage>(r => (int)r.StatusCode >= 500)
          .WaitAndRetryAsync(3, retryAttempt => 
              TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

// Использование
HttpResponseMessage response = await retryPolicy.ExecuteAsync(() =>
    client.GetAsync("https://api.example.com/data"));

4. Продвинутые техники: потоковая передача и отмена запросов

Для работы с большими файлами или длинными ответами используйте потоковую передачу, чтобы не загружать всё в память:

using (var stream = await response.Content.ReadAsStreamAsync())
{
    // Читаем поток, например, сохраняем в файл
    using (var fileStream = File.Create("largefile.dat"))
    {
        await stream.CopyToAsync(fileStream);
    }
}

Отмена запросов через CancellationToken критична для UI-приложений и микросервисов:

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); // таймаут для запроса

try
{
    var response = await client.GetAsync("https://api.example.com", cts.Token);
    // Обработка
}
catch (OperationCanceledException)
{
    Console.WriteLine("Запрос был отменён или превышен таймаут");
}

                
                

Блоги

Рекомендаций по книгам