Руководство по миграции HttpWebRequest в HttpClient
Эта статья направлена на руководство разработчиков по процессу миграции с HttpWebRequest, ServicePointа также ServicePointManager на HttpClient. Миграция необходима из-за устаревания старых API и многочисленных преимуществ, предлагаемых HttpClient, включая повышение производительности, улучшение управления ресурсами и более современную и гибкую структуру API. Следуя инструкциям, описанным в этом документе, разработчики смогут плавно перенести свои базы кода и воспользоваться всеми преимуществами функций, предоставляемых HttpClientв этом документе.
Предупреждение
Переход с HttpWebRequest
, ServicePoint
и ServicePointManager
не HttpClient
только "приятно иметь" повышение производительности. Важно понимать, что производительность существующей WebRequest
логики может значительно снизиться после перехода на .NET (Core). Это связано с тем, что WebRequest
поддерживается как минимальный уровень совместимости, что означает, что он не имеет большого количества оптимизаций, таких как повторное использование подключения во многих случаях. Таким образом, переход HttpClient
на важный для обеспечения производительности и управления ресурсами приложения соответствует современным стандартам.
Переход из HttpWebRequestHttpClient
Начнем с некоторых примеров:
Простой запрос GET с помощью HttpWebRequest
Ниже приведен пример того, как может выглядеть код:
HttpWebRequest request = WebRequest.CreateHttp(uri);
using WebResponse response = await request.GetResponseAsync();
Простой запрос GET с помощью HttpClient
Ниже приведен пример того, как может выглядеть код:
HttpClient client = new();
using HttpResponseMessage message = await client.GetAsync(uri);
Простой запрос POST с помощью HttpWebRequest
Ниже приведен пример того, как может выглядеть код:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.Method = "POST";
request.ContentType = "text/plain";
await using Stream stream = await request.GetRequestStreamAsync();
await stream.WriteAsync("Hello World!"u8.ToArray());
using WebResponse response = await request.GetResponseAsync();
Простой запрос POST с помощью HttpClient
Ниже приведен пример того, как может выглядеть код:
HttpClient client = new();
using HttpResponseMessage responseMessage = await client.PostAsync(uri, new StringContent("Hello World!"));
Руководство по миграции HttpWebRequest в HttpClient, SocketsHttpHandler
HttpWebRequest Старый API | Новый API | Примечания. |
---|---|---|
Accept |
Accept | Пример. Установка заголовков запросов. |
Address |
RequestUri | Пример. Получение перенаправленного URI. |
AllowAutoRedirect |
AllowAutoRedirect | Пример. Задание свойств SocketsHttpHandler. |
AllowReadStreamBuffering |
Нет прямого эквивалентного API | Использование свойств буферизации. |
AllowWriteStreamBuffering |
Нет прямого эквивалентного API | Использование свойств буферизации. |
AuthenticationLevel |
Нет прямого эквивалентного API | Пример. Включение взаимной проверки подлинности. |
AutomaticDecompression |
AutomaticDecompression | Пример. Задание свойств SocketsHttpHandler. |
CachePolicy |
Нет прямого эквивалентного API | Пример. Применение заголовков CachePolicy. |
ClientCertificates |
SslOptions.ClientCertificates | Использование свойств, связанных с сертификатом в HttpClient. |
Connection |
Connection | Пример. Установка заголовков запросов. |
ConnectionGroupName |
Нет эквивалентного API | Обходной путь |
ContentLength |
ContentLength | Пример. Задание заголовков содержимого. |
ContentType |
ContentType | Пример. Задание заголовков содержимого. |
ContinueDelegate |
Нет эквивалентного API | Обходное решение отсутствует. |
ContinueTimeout |
Expect100ContinueTimeout | Пример. Задание свойств SocketsHttpHandler. |
CookieContainer |
CookieContainer | Пример. Задание свойств SocketsHttpHandler. |
Credentials |
Credentials | Пример. Задание свойств SocketsHttpHandler. |
Date |
Date | Пример. Установка заголовков запросов. |
DefaultCachePolicy |
Нет прямого эквивалентного API | Пример. Применение заголовков CachePolicy. |
DefaultMaximumErrorResponseLength |
Нет прямого эквивалентного API | Пример. Задание MaximumErrorResponseLength в HttpClient. |
DefaultMaximumResponseHeadersLength |
Нет эквивалентного API | MaxResponseHeadersLength вместо этого можно использовать. |
DefaultWebProxy |
Нет эквивалентного API | Proxy вместо этого можно использовать. |
Expect |
Expect | Пример. Установка заголовков запросов. |
HaveResponse |
Нет эквивалентного API | Подразумевается наличие экземпляра HttpResponseMessage . |
Headers |
Headers | Пример. Установка заголовков запросов. |
Host |
Host | Пример. Установка заголовков запросов. |
IfModifiedSince |
IfModifiedSince | Пример. Установка заголовков запросов. |
ImpersonationLevel |
Нет прямого эквивалентного API | Пример: изменение олицетворенияLevel. |
KeepAlive |
Нет прямого эквивалентного API | Пример. Установка заголовков запросов. |
MaximumAutomaticRedirections |
MaxAutomaticRedirections | Пример. Задание свойств SocketsHttpHandler. |
MaximumResponseHeadersLength |
MaxResponseHeadersLength | Пример. Задание свойств SocketsHttpHandler. |
MediaType |
Нет прямого эквивалентного API | Пример. Задание заголовков содержимого. |
Method |
Method | Пример: использование свойств HttpRequestMessage. |
Pipelined |
Нет эквивалентного API | HttpClient не поддерживает конвейерную структуру. |
PreAuthenticate |
PreAuthenticate | |
ProtocolVersion |
HttpRequestMessage.Version |
Пример: использование свойств HttpRequestMessage. |
Proxy |
Proxy | Пример. Задание свойств SocketsHttpHandler. |
ReadWriteTimeout |
Нет прямого эквивалентного API | Использование SocketsHttpHandler и ConnectCallback. |
Referer |
Referrer | Пример. Установка заголовков запросов. |
RequestUri |
RequestUri | Пример: использование свойств HttpRequestMessage. |
SendChunked |
TransferEncodingChunked | Пример. Установка заголовков запросов. |
ServerCertificateValidationCallback |
SslOptions.RemoteCertificateValidationCallback | Пример. Задание свойств SocketsHttpHandler. |
ServicePoint |
Нет эквивалентного API | ServicePoint не является частью HttpClient . |
SupportsCookieContainer |
Нет эквивалентного API | Это всегда для true HttpClient . |
Timeout |
Timeout | |
TransferEncoding |
TransferEncoding | Пример. Установка заголовков запросов. |
UnsafeAuthenticatedConnectionSharing |
Нет эквивалентного API | Обходной путь |
UseDefaultCredentials |
Нет прямого эквивалентного API | Пример. Задание свойств SocketsHttpHandler. |
UserAgent |
UserAgent | Пример. Установка заголовков запросов. |
Перенос использования ServicePoint(Manager)
Следует учитывать, что ServicePointManager
является статическим классом, то есть любые изменения, внесенные в его свойства, будут иметь глобальное влияние на все вновь созданные ServicePoint
объекты в приложении. Например, при изменении свойства, например ConnectionLimit
, Expect100Continue
это влияет на каждый новый экземпляр ServicePoint.
Предупреждение
В современной .NET HttpClient
не учитывает конфигурации, установленные в ServicePointManager
.
ServicePointManager Сопоставление свойств
Предупреждение
В современном .NET значения по умолчанию для UseNagleAlgorithm
свойств и Expect100Continue
свойств заданы false
. Эти значения были true
по умолчанию в платформа .NET Framework.
ServicePointManager Сопоставление методов
ServicePointManager Старый API | Новый API | Примечания. |
---|---|---|
FindServicePoint |
Нет эквивалентного API | Обходной путь |
SetTcpKeepAlive |
Нет прямого эквивалентного API | Использование SocketsHttpHandler и ConnectCallback. |
ServicePoint Сопоставление свойств
ServicePoint Старый API | Новый API | Примечания. |
---|---|---|
Address |
HttpRequestMessage.RequestUri |
Это URI запроса, эти сведения можно найти в разделе HttpRequestMessage . |
BindIPEndPointDelegate |
Нет прямого эквивалентного API | Использование SocketsHttpHandler и ConnectCallback. |
Certificate |
Нет прямого эквивалентного API | Эти сведения можно получить из RemoteCertificateValidationCallback . Пример: получение сертификата. |
ClientCertificate |
Нет эквивалентного API | Пример. Включение взаимной проверки подлинности. |
ConnectionLeaseTimeout |
SocketsHttpHandler.PooledConnectionLifetime |
Эквивалентный параметр в HttpClient |
ConnectionLimit |
MaxConnectionsPerServer | Пример. Задание свойств SocketsHttpHandler. |
ConnectionName |
Нет эквивалентного API | Обходной путь |
CurrentConnections |
Нет эквивалентного API | См . сведения о телеметрии сети в .NET. |
Expect100Continue |
ExpectContinue | Пример. Установка заголовков запросов. |
IdleSince |
Нет эквивалентного API | Обходной путь |
MaxIdleTime |
PooledConnectionIdleTimeout | Пример. Задание свойств SocketsHttpHandler. |
ProtocolVersion |
HttpRequestMessage.Version |
Пример: использование свойств HttpRequestMessage. |
ReceiveBufferSize |
Нет прямого эквивалентного API | Использование SocketsHttpHandler и ConnectCallback. |
SupportsPipelining |
Нет эквивалентного API | HttpClient не поддерживает конвейерную структуру. |
UseNagleAlgorithm |
Нет прямого эквивалентного API | Использование SocketsHttpHandler и ConnectCallback. |
ServicePoint Сопоставление методов
ServicePoint Старый API | Новый API | Примечания. |
---|---|---|
CloseConnectionGroup |
Нет эквивалента | Обходной путь |
SetTcpKeepAlive |
Нет прямого эквивалентного API | Использование SocketsHttpHandler и ConnectCallback. |
Использование свойств HttpClient и HttpRequestMessage
При работе с HttpClient в .NET у вас есть доступ к различным свойствам, которые позволяют настраивать и настраивать HTTP-запросы и ответы. Общие сведения об этих свойствах помогут вам получить большую часть HttpClient и обеспечить эффективную и безопасную связь приложения с веб-службами.
Пример. Использование свойств HttpRequestMessage
Ниже приведен пример использования HttpClient и HttpRequestMessage:
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://example.com"); // Method and RequestUri usage
var request = new HttpRequestMessage() // Alternative way to set RequestUri and Method
{
RequestUri = new Uri("https://example.com"),
Method = HttpMethod.Post
};
request.Headers.Add("Custom-Header", "value");
request.Content = new StringContent("somestring");
using var response = await client.SendAsync(request);
var protocolVersion = response.RequestMessage.Version; // Fetch `ProtocolVersion`.
Пример. Получение перенаправленного URI
Ниже приведен пример получения перенаправленного URI (аналогично HttpWebRequest.Address
):
var client = new HttpClient();
using var response = await client.GetAsync(uri);
var redirectedUri = response.RequestMessage.RequestUri;
Использование SocketsHttpHandler и ConnectCallback
Это ConnectCallback
свойство SocketsHttpHandler
позволяет разработчикам настраивать процесс установления TCP-подключения. Это может быть полезно для сценариев, когда необходимо управлять разрешением DNS или применять определенные параметры сокета к подключению. С помощью ConnectCallback
можно перехватывать и изменять процесс подключения, прежде чем он будет использоваться HttpClient
.
Пример. Привязка IP-адреса к сокету
В старом подходе, HttpWebRequest
возможно, вы использовали пользовательскую логику для привязки определенного IP-адреса к сокету. Вот как можно реализовать аналогичные функциональные возможности с помощью HttpClient
и ConnectCallback
:
Старый код с помощью HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) =>
{
// Bind to a specific IP address
IPAddress localAddress = IPAddress.Parse("192.168.1.100");
return new IPEndPoint(localAddress, 0);
};
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Использование нового кода HttpClient
и ConnectCallback
:
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellationToken) =>
{
// Bind to a specific IP address
IPAddress localAddress = IPAddress.Parse("192.168.1.100");
var socket = new Socket(localAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Bind(new IPEndPoint(localAddress, 0));
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Пример. Применение определенных параметров сокета
Если вам нужно применить определенные параметры сокета, например включение обеспечения работоспособности TCP, можно использовать ConnectCallback
для настройки сокета, прежде чем он будет использоваться HttpClient
. На самом деле, ConnectCallback
более гибким является настройка параметров сокета.
Старый код с помощью HttpWebRequest
:
ServicePointManager.ReusePort = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.ServicePoint.SetTcpKeepAlive(true, 60000, 1000);
request.ServicePoint.ReceiveBufferSize = 8192;
request.ServicePoint.UseNagleAlgorithm = false;
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Использование нового кода HttpClient
и ConnectCallback
:
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellationToken) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
try
{
// Setting TCP Keep Alive
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 60);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1);
// Setting ReceiveBufferSize
socket.ReceiveBufferSize = 8192;
// Enabling ReusePort
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
// Disabling Nagle Algorithm
socket.NoDelay = true;
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Пример. Включение циклического перебора DNS
Dns Round Robin — это метод, используемый для распределения сетевого трафика между несколькими серверами путем поворота списка IP-адресов, связанных с одним доменным именем. Это помогает в балансировке нагрузки и повышении доступности служб. При использовании HttpClient можно реализовать DNS Round Robin, вручную обрабатывая разрешение DNS и вращаясь по IP-адресам с помощью свойства ConnectCallback SocketsHttpHandler.
Чтобы включить DNS Round Robin с помощью HttpClient, можно использовать свойство ConnectCallback для ручного разрешения записей DNS и поворота через IP-адреса. Ниже приведен пример HttpWebRequest
для и HttpClient
:
Старый код с помощью HttpWebRequest
:
ServicePointManager.DnsRefreshTimeout = 60000;
ServicePointManager.EnableDnsRoundRobin = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
В более старой HttpWebRequest
версии API включение DNS Round Robin было простым из-за встроенной поддержки этой функции. Однако более новый HttpClient
API не предоставляет одни и те же встроенные функции. Несмотря на это, можно добиться аналогичного поведения, реализовав DnsRoundRobinConnector
, что вручную поворачивается через IP-адреса, возвращаемые разрешением DNS.
Новый код с помощью HttpClient
:
// This is available as NuGet Package: https://www.nuget.org/packages/DnsRoundRobin/
// The original source code can be found also here: https://github.com/MihaZupan/DnsRoundRobin
public sealed class DnsRoundRobinConnector : IDisposable
Здесь можно найти реализацию DnsRoundRobinConnector
.
DnsRoundRobinConnector
Употребление:
private static readonly DnsRoundRobinConnector s_roundRobinConnector = new(
dnsRefreshInterval: TimeSpan.FromSeconds(10),
endpointConnectTimeout: TimeSpan.FromSeconds(5));
static async Task DnsRoundRobinConnectAsync()
{
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellation) =>
{
Socket socket = await DnsRoundRobinConnector.Shared.ConnectAsync(context.DnsEndPoint, cancellation);
// Or you can create and use your custom DnsRoundRobinConnector instance
// Socket socket = await s_roundRobinConnector.ConnectAsync(context.DnsEndPoint, cancellation);
return new NetworkStream(socket, ownsSocket: true);
}
};
var client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(Uri);
}
Пример. Задание свойств SocketsHttpHandler
SocketsHttpHandler — это мощный и гибкий обработчик в .NET, который предоставляет расширенные параметры конфигурации для управления HTTP-подключениями. Задав различные свойства SocketsHttpHandler, вы можете точно настроить поведение http-клиента в соответствии с конкретными требованиями, такими как оптимизация производительности, улучшения безопасности и настраиваемая обработка подключений.
Ниже приведен пример настройки SocketsHttpHandler с различными свойствами и его использования с HttpClient:
var cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("cookieName", "cookieValue"));
var handler = new SocketsHttpHandler
{
AllowAutoRedirect = true,
AutomaticDecompression = DecompressionMethods.All,
Expect100ContinueTimeout = TimeSpan.FromSeconds(1),
CookieContainer = cookieContainer,
Credentials = new NetworkCredential("user", "pass"),
MaxAutomaticRedirections = 10,
MaxResponseHeadersLength = 1,
Proxy = new WebProxy("http://proxyserver:8080"), // Don't forget to set UseProxy
UseProxy = true,
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Пример. Изменение олицетворенияLevel
Эта функция зависит от определенных платформ и несколько устарела. Если вам нужен обходной путь, обратитесь к этому разделу кода.
Использование свойств сертификата и TLS в HttpClient
При работе HttpClient
с ними может потребоваться обрабатывать сертификаты клиента для различных целей, например настраиваемую проверку сертификатов сервера или получение сертификата сервера. HttpClient
предоставляет несколько свойств и вариантов эффективного управления сертификатами.
Пример. Проверка списка отзыва сертификатов с помощью SocketsHttpHandler
Это CheckCertificateRevocationList
свойство SocketsHttpHandler.SslOptions
позволяет разработчикам включить или отключить проверку списков отзыва сертификатов (CRL) во время подтверждения SSL/TLS. Включение этого свойства гарантирует, что клиент проверяет, был ли отозван сертификат сервера, повышая безопасность подключения.
Старый код с помощью HttpWebRequest
:
ServicePointManager.CheckCertificateRevocationList = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Новый код с помощью HttpClient
:
bool checkCertificateRevocationList = true;
var handler = new SocketsHttpHandler
{
SslOptions =
{
CertificateRevocationCheckMode = checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Пример: получение сертификата
Чтобы получить сертификат из in RemoteCertificateValidationCallback
HttpClient
, можно использовать ServerCertificateCustomValidationCallback
свойство HttpClientHandler
или SocketsHttpHandler.SslOptions
. Этот обратный вызов позволяет проверить сертификат сервера во время подтверждения SSL/TLS.
Старый код с помощью HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
X509Certificate? serverCertificate = request.ServicePoint.Certificate;
Новый код с помощью HttpClient
:
X509Certificate? serverCertificate = null;
var handler = new SocketsHttpHandler
{
SslOptions = new SslClientAuthenticationOptions
{
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
serverCertificate = certificate;
// Leave the validation as-is.
return sslPolicyErrors == SslPolicyErrors.None;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync("https://example.com");
Пример. Включение взаимной проверки подлинности
Взаимная проверка подлинности, также известная как двухсторонняя проверка подлинности SSL или сертификата клиента, — это процесс безопасности, в котором клиент и сервер проходят проверку подлинности друг друга. Это гарантирует, что обе стороны являются тем, кто они утверждают, обеспечивая дополнительный уровень безопасности для конфиденциальной связи. В HttpClient
этом случае можно включить взаимную проверку подлинности, настроив HttpClientHandler
или SocketsHttpHandler
включив сертификат клиента и проверив сертификат сервера.
Чтобы включить взаимную проверку подлинности, выполните следующие действия.
- Загрузите сертификат клиента.
- Настройте HttpClientHandler или SocketsHttpHandler, чтобы включить сертификат клиента.
- Настройте обратный вызов проверки сертификата сервера, если требуется настраиваемая проверка.
Ниже приведен пример использования SocketsHttpHandler:
var handler = new SocketsHttpHandler
{
SslOptions = new SslClientAuthenticationOptions
{
ClientCertificates = new X509CertificateCollection
{
// Load the client certificate from a file
new X509Certificate2("path_to_certificate.pfx", "certificate_password")
},
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
// Custom validation logic for the server certificate
return sslPolicyErrors == SslPolicyErrors.None;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
Использование свойств заголовка
Заголовки играют важную роль в обмене данными ПО HTTP, предоставляя необходимые метаданные о запросе и ответе. При работе с HttpClient
.NET можно задать различные свойства заголовка и управлять ими, чтобы управлять поведением HTTP-запросов и ответов. Понимание того, как эффективно использовать эти свойства заголовков, поможет обеспечить эффективное и безопасное взаимодействие приложения с веб-службами.
Установка заголовков запросов
Заголовки запросов используются для предоставления дополнительных сведений серверу о выполняемом запросе. Распространенные варианты использования включают указание типа контента, настройка маркеров проверки подлинности и добавление пользовательских заголовков. Вы можете задать заголовки запросов с помощью DefaultRequestHeaders
свойства HttpClient
или свойства HttpRequestMessage
Headers .
Пример. Настройка заголовков пользовательских запросов
Настройка заголовков пользовательских запросов по умолчанию в HttpClient
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Custom-Header", "value");
Настройка пользовательских заголовков запросов в HttpRequestMessage
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("Custom-Header", "value");
Пример. Настройка общих заголовков запросов
При работе с HttpRequestMessage
.NET настройка общих заголовков запросов необходима для предоставления дополнительных сведений серверу о выполняемом запросе. Эти заголовки могут включать маркеры проверки подлинности и многое другое. Правильная настройка этих заголовков гарантирует правильность обработки HTTP-запросов сервером.
Полный список общих свойств, доступных в HttpRequestHeadersразделе "Свойства".
Чтобы задать общие заголовки HttpRequestMessage
запросов, можно использовать Headers
свойство HttpRequestMessage
объекта. Это свойство предоставляет доступ к HttpRequestHeaders
коллекции, где можно добавлять или изменять заголовки по мере необходимости.
Настройка общих заголовков запросов по умолчанию в HttpClient
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Настройка общих заголовков запросов в HttpRequestMessage
using System.Net.Http.Headers;
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Пример. Задание заголовков содержимого
Заголовки контента используются для предоставления дополнительных сведений о тексте HTTP-запроса или ответа. При работе с .NET можно задать заголовки содержимого, чтобы указать тип носителя, кодировку и другие метаданные, связанные с HttpClient
отправленным или полученным содержимым. Правильная настройка заголовков содержимого гарантирует правильность интерпретации и обработки содержимого сервером и клиентом.
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, uri);
// Create the content and set the content headers
var jsonData = "{\"key\":\"value\"}";
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
// The following headers are set automatically by `StringContent`. If you wish to override their values, you can do it like so:
// content.Headers.ContentType = new MediaTypeHeaderValue("application/json; charset=utf-8");
// content.Headers.ContentLength = Encoding.UTF8.GetByteCount(jsonData);
// Assign the content to the request
request.Content = content;
using var response = await client.SendAsync(request);
Пример. Задание MaximumErrorResponseLength в HttpClient
Использование MaximumErrorResponseLength
позволяет разработчикам указать максимальную длину содержимого ответа об ошибке, которое будет буферизировать обработчик. Это полезно для управления объемом данных, которые считываются и хранятся в памяти при получении ответа об ошибке от сервера. С помощью этого метода можно предотвратить чрезмерное использование памяти и повысить производительность приложения при обработке больших ответов на ошибки.
Существует несколько способов сделать это, мы рассмотрим TruncatedReadStream
методику в этом примере:
internal sealed class TruncatedReadStream(Stream innerStream, long maxSize) : Stream
{
private long _maxRemainingLength = maxSize;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override void Flush() => throw new NotSupportedException();
public override int Read(byte[] buffer, int offset, int count)
{
return Read(new Span<byte>(buffer, offset, count));
}
public override int Read(Span<byte> buffer)
{
int readBytes = innerStream.Read(buffer.Slice(0, (int)Math.Min(buffer.Length, _maxRemainingLength)));
_maxRemainingLength -= readBytes;
return readBytes;
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
int readBytes = await innerStream.ReadAsync(buffer.Slice(0, (int)Math.Min(buffer.Length, _maxRemainingLength)), cancellationToken)
.ConfigureAwait(false);
_maxRemainingLength -= readBytes;
return readBytes;
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override ValueTask DisposeAsync() => innerStream.DisposeAsync();
protected override void Dispose(bool disposing)
{
if (disposing)
{
innerStream.Dispose();
}
}
}
Пример использования TruncatedReadStream
:
int maxErrorResponseLength = 1 * 1024; // 1 KB
HttpClient client = new HttpClient();
using HttpResponseMessage response = await client.GetAsync(Uri);
if (response.Content is not null)
{
Stream responseReadStream = await response.Content.ReadAsStreamAsync();
// If MaxErrorResponseLength is set and the response status code is an error code, then wrap the response stream in a TruncatedReadStream
if (maxErrorResponseLength >= 0 && !response.IsSuccessStatusCode)
{
responseReadStream = new TruncatedReadStream(responseReadStream, maxErrorResponseLength);
}
// Read the response stream
Memory<byte> buffer = new byte[1024];
int readValue = await responseReadStream.ReadAsync(buffer);
}
Пример. Применение заголовков CachePolicy
Предупреждение
HttpClient
не имеет встроенной логики для кэширования ответов. Обходной путь, отличный от реализации всего кэширования самостоятельно. Простое задание заголовков не приведет к кэшированию.
При миграции из HttpWebRequest
HttpClient
нее важно правильно обрабатывать заголовки, связанные с кэшем, pragma
например и cache-control
. Эти заголовки определяют, как кэшируются и извлекаются ответы, гарантируя, что ваше приложение работает должным образом с точки зрения производительности и свежести данных.
Возможно HttpWebRequest
, вы использовали CachePolicy
свойство для задания этих заголовков. Однако в HttpClient
запросе необходимо вручную задать эти заголовки.
Старый код с помощью HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
В более старой HttpWebRequest
версии API применение CachePolicy
было простым из-за встроенной поддержки этой функции. Однако более новый HttpClient
API не предоставляет одни и те же встроенные функции. Несмотря на это, можно добиться аналогичного AddCacheControlHeaders
поведения, реализовав, что вручную добавляет связанные заголовки кэша.
Новый код с помощью HttpClient
:
public static class CachePolicy
{
public static void AddCacheControlHeaders(HttpRequestMessage request, RequestCachePolicy policy)
Здесь можно найти реализацию AddCacheControlHeaders
.
AddCacheControlHeaders
Употребление:
static async Task AddCacheControlHeaders()
{
HttpClient client = new HttpClient();
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, Uri);
CachePolicy.AddCacheControlHeaders(requestMessage, new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore));
HttpResponseMessage response = await client.SendAsync(requestMessage);
}
Использование свойств буферизации
При миграции из HttpWebRequest HttpClient
в , важно понимать различия в том, как эти два API обрабатывают буферизацию.
Старый код с помощью HttpWebRequest
:
В HttpWebRequest
этом случае у вас есть прямой контроль над буферизацией свойств с помощью AllowWriteStreamBuffering
и AllowReadStreamBuffering
свойств. Эти свойства позволяют включить или отключить буферизацию данных, отправляемых и полученных с сервера.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowReadStreamBuffering = true; // Default is `false`.
request.AllowWriteStreamBuffering = false; // Default is `true`.
Новый код с помощью HttpClient
:
В HttpClient
ней нет прямых эквивалентов AllowWriteStreamBuffering
свойств и AllowReadStreamBuffering
свойств.
HttpClient не буферизирует тела запросов самостоятельно, а не делегирует ответственность за использованное HttpContent
. Содержимое, подобное или ByteArrayContent
логическое, уже буферизованное в памяти, в то время как StringContent
использование StreamContent
не приведет к буферизации по умолчанию. Чтобы принудительно буферизовать содержимое, можно вызвать HttpContent.LoadIntoBufferAsync
перед отправкой запроса. Приведем пример:
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StreamContent(yourStream);
await request.Content.LoadIntoBufferAsync();
HttpResponseMessage response = await client.SendAsync(request);
В HttpClient
буферизации чтения включена по умолчанию. Чтобы избежать этого, можно указать HttpCompletionOption.ResponseHeadersRead
флаг или использовать вспомогательный GetStreamAsync
элемент.
HttpClient client = new HttpClient();
using HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
await using Stream responseStream = await response.Content.ReadAsStreamAsync();
// Or simply
await using Stream responseStream = await client.GetStreamAsync(uri);