Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten artykuł ma na celu poprowadzenie deweloperów przez proces migracji z HttpWebRequestsystemu , ServicePointi ServicePointManager do HttpClient. Migracja jest konieczna ze względu na przestarzałe interfejsy API i liczne korzyści oferowane przez HttpClientusługę , w tym lepszą wydajność, lepsze zarządzanie zasobami oraz bardziej nowoczesny i elastyczny projekt interfejsu API. Wykonując kroki opisane w tym dokumencie, deweloperzy będą mogli bezproblemowo przenosić bazy kodu i korzystać z funkcji udostępnianych przez HttpClientprogram .
Ostrzeżenie
Migrowanie z HttpWebRequestelementu , ServicePointi ServicePointManager do HttpClient nie jest tylko "miłą wydajnością". Ważne jest, aby zrozumieć, że wydajność istniejącej WebRequest logiki może znacznie obniżyć się po przejściu do platformy .NET (Core). Dzieje się tak dlatego, że WebRequest jest utrzymywana jako minimalna warstwa zgodności, co oznacza, że brakuje wielu optymalizacji, takich jak ponowne użycie połączenia w wielu przypadkach. W związku z tym przejście do HttpClient systemu jest niezbędne, aby zapewnić, że wydajność aplikacji i zarządzanie zasobami są zgodne z nowoczesnymi standardami.
Migrowanie z HttpWebRequest do HttpClient
Zacznijmy od kilku przykładów:
Proste żądanie GET przy użyciu polecenia HttpWebRequest
Oto przykładowy wygląd kodu:
HttpWebRequest request = WebRequest.CreateHttp(uri);
using WebResponse response = await request.GetResponseAsync();
Proste żądanie GET przy użyciu polecenia HttpClient
Oto przykładowy wygląd kodu:
HttpClient client = new();
using HttpResponseMessage message = await client.GetAsync(uri);
Proste żądanie POST przy użyciu polecenia HttpWebRequest
Oto przykładowy wygląd kodu:
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();
Proste żądanie POST przy użyciu polecenia HttpClient
Oto przykładowy wygląd kodu:
HttpClient client = new();
using HttpResponseMessage responseMessage = await client.PostAsync(uri, new StringContent("Hello World!"));
HttpWebRequest do HttpClient, SocketsHttpHandler przewodnik migracji
| HttpWebRequest Stary interfejs API | Nowy interfejs API | Uwagi |
|---|---|---|
Accept |
Accept | Przykład: ustawianie nagłówków żądań. |
Address |
RequestUri | Przykład: pobieranie identyfikatora URI przekierowanego. |
AllowAutoRedirect |
AllowAutoRedirect | Przykład: ustawianie właściwości SocketsHttpHandler. |
AllowReadStreamBuffering |
Brak bezpośredniego odpowiednika interfejsu API | Użycie właściwości buforowania. |
AllowWriteStreamBuffering |
Brak bezpośredniego odpowiednika interfejsu API | Użycie właściwości buforowania. |
AuthenticationLevel |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: włączanie wzajemnego uwierzytelniania. |
AutomaticDecompression |
AutomaticDecompression | Przykład: ustawianie właściwości SocketsHttpHandler. |
CachePolicy |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: Zastosuj nagłówki CachePolicy. |
ClientCertificates |
SslOptions.ClientCertificates | Użycie właściwości powiązanych z certyfikatami w programie HttpClient. |
Connection |
Connection | Przykład: ustawianie nagłówków żądań. |
ConnectionGroupName |
Brak równoważnego interfejsu API | Brak obejścia |
ContentLength |
ContentLength | Przykład: ustawianie nagłówków zawartości. |
ContentType |
ContentType | Przykład: ustawianie nagłówków zawartości. |
ContinueDelegate |
Brak równoważnego interfejsu API | Brak obejścia. |
ContinueTimeout |
Expect100ContinueTimeout | Przykład: ustaw właściwości SocketsHttpHandler. |
CookieContainer |
CookieContainer | Przykład: ustaw właściwości SocketsHttpHandler. |
Credentials |
Credentials | Przykład: ustaw właściwości SocketsHttpHandler. |
Date |
Date | Przykład: ustawianie nagłówków żądań. |
DefaultCachePolicy |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: Zastosuj nagłówki CachePolicy. |
DefaultMaximumErrorResponseLength |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: ustaw wartość MaximumErrorResponseLength w obiekcie HttpClient. |
DefaultMaximumResponseHeadersLength |
Brak równoważnego interfejsu API | MaxResponseHeadersLength Zamiast tego można użyć polecenia . |
DefaultWebProxy |
Brak równoważnego interfejsu API | Proxy Zamiast tego można użyć polecenia . |
Expect |
Expect | Przykład: ustawianie nagłówków żądań. |
HaveResponse |
Brak równoważnego interfejsu API | Implikowane przez wystąpienie HttpResponseMessage . |
Headers |
Headers | Przykład: ustawianie nagłówków żądań. |
Host |
Host | Przykład: ustawianie nagłówków żądań. |
IfModifiedSince |
IfModifiedSince | Przykład: ustawianie nagłówków żądań. |
ImpersonationLevel |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: Zmiana personifikacjiLevel. |
KeepAlive |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: ustawianie nagłówków żądań. |
MaximumAutomaticRedirections |
MaxAutomaticRedirections | Przykład: ustawianie właściwości SocketsHttpHandler. |
MaximumResponseHeadersLength |
MaxResponseHeadersLength | Przykład: ustawianie właściwości SocketsHttpHandler. |
MediaType |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: ustawianie nagłówków zawartości. |
Method |
Method | Przykład: użycie właściwości HttpRequestMessage. |
Pipelined |
Brak równoważnego interfejsu API |
HttpClient nie obsługuje potokowania. |
PreAuthenticate |
PreAuthenticate | |
ProtocolVersion |
HttpRequestMessage.Version |
Przykład: użycie właściwości HttpRequestMessage. |
Proxy |
Proxy | Przykład: ustawianie właściwości SocketsHttpHandler. |
ReadWriteTimeout |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
Referer |
Referrer | Przykład: ustawianie nagłówków żądań. |
RequestUri |
RequestUri | Przykład: użycie właściwości HttpRequestMessage. |
SendChunked |
TransferEncodingChunked | Przykład: ustawianie nagłówków żądań. |
ServerCertificateValidationCallback |
SslOptions.RemoteCertificateValidationCallback | Przykład: ustawianie właściwości SocketsHttpHandler. |
ServicePoint |
Brak równoważnego interfejsu API |
ServicePoint nie jest częścią elementu HttpClient. |
SupportsCookieContainer |
Brak równoważnego interfejsu API | Jest to zawsze true dla elementu HttpClient. |
Timeout |
Timeout | |
TransferEncoding |
TransferEncoding | Przykład: ustawianie nagłówków żądań. |
UnsafeAuthenticatedConnectionSharing |
Brak równoważnego interfejsu API | Brak obejścia |
UseDefaultCredentials |
Brak bezpośredniego odpowiednika interfejsu API | Przykład: ustawianie właściwości SocketsHttpHandler. |
UserAgent |
UserAgent | Przykład: ustawianie nagłówków żądań. |
Zmień użycie ServicePointManager
Należy pamiętać, że jest to klasa statyczna, co oznacza, że ServicePointManager wszelkie zmiany wprowadzone w jej właściwościach będą miały globalny wpływ na wszystkie nowo utworzone ServicePoint obiekty w aplikacji. Na przykład podczas modyfikowania właściwości takiej jak ConnectionLimit lub Expect100Continue, ma to wpływ na każde nowe ServicePoint wystąpienie.
Ostrzeżenie
W nowoczesnym środowisku .NET HttpClient nie uwzględnia żadnych konfiguracji ustawionych na platformie ServicePointManager.
ServicePointManager mapowanie właściwości
| ServicePointManager Stary interfejs API | Nowy interfejs API | Uwagi |
|---|---|---|
CheckCertificateRevocationList |
SslOptions.CertificateRevocationCheckMode | Przykład: włączanie sprawdzania listy CRL przy użyciu protokołu SocketsHttpHandler. |
DefaultConnectionLimit |
MaxConnectionsPerServer | Przykład: ustawianie właściwości SocketsHttpHandler. |
DnsRefreshTimeout |
Brak równoważnego interfejsu API | Przykład: włączanie działania okrężnego dns. |
EnableDnsRoundRobin |
Brak równoważnego interfejsu API | Przykład: włączanie działania okrężnego dns. |
EncryptionPolicy |
SslOptions.EncryptionPolicy | Przykład: ustawianie właściwości SocketsHttpHandler. |
Expect100Continue |
ExpectContinue | Przykład: ustawianie nagłówków żądań. |
MaxServicePointIdleTime |
PooledConnectionIdleTimeout | Przykład: ustawianie właściwości SocketsHttpHandler. |
MaxServicePoints |
Brak równoważnego interfejsu API |
ServicePoint nie jest częścią elementu HttpClient. |
ReusePort |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
SecurityProtocol |
SslOptions.EnabledSslProtocols | Przykład: ustawianie właściwości SocketsHttpHandler. |
ServerCertificateValidationCallback |
SslOptions.RemoteCertificateValidationCallback | Oba są RemoteCertificateValidationCallback |
UseNagleAlgorithm |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
Ostrzeżenie
W nowoczesnej platformie .NET wartości domyślne właściwości UseNagleAlgorithm i Expect100Continue są ustawione na false. Te wartości były true domyślnie dostępne w programie .NET Framework.
ServicePointManager mapowanie metody
| ServicePointManager Stary interfejs API | Nowy interfejs API | Uwagi |
|---|---|---|
FindServicePoint |
Brak równoważnego interfejsu API | Brak obejścia |
SetTcpKeepAlive |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
ServicePoint mapowanie właściwości
| ServicePoint Stary interfejs API | Nowy interfejs API | Uwagi |
|---|---|---|
Address |
HttpRequestMessage.RequestUri |
Jest to identyfikator URI żądania. Te informacje można znaleźć w obszarze HttpRequestMessage. |
BindIPEndPointDelegate |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
Certificate |
Brak bezpośredniego odpowiednika interfejsu API | Te informacje można pobrać z witryny RemoteCertificateValidationCallback.
Przykład: pobieranie certyfikatu. |
ClientCertificate |
Brak równoważnego interfejsu API | Przykład: włączanie wzajemnego uwierzytelniania. |
ConnectionLeaseTimeout |
SocketsHttpHandler.PooledConnectionLifetime |
Ustawienie równoważne w elemencie HttpClient |
ConnectionLimit |
MaxConnectionsPerServer | Przykład: ustawianie właściwości SocketsHttpHandler. |
ConnectionName |
Brak równoważnego interfejsu API | Brak obejścia |
CurrentConnections |
Brak równoważnego interfejsu API | Zobacz Telemetria sieciowa na platformie .NET. |
Expect100Continue |
ExpectContinue | Przykład: ustawianie nagłówków żądań. |
IdleSince |
Brak równoważnego interfejsu API | Brak obejścia |
MaxIdleTime |
PooledConnectionIdleTimeout | Przykład: ustawianie właściwości SocketsHttpHandler. |
ProtocolVersion |
HttpRequestMessage.Version |
Przykład: użycie właściwości HttpRequestMessage. |
ReceiveBufferSize |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
SupportsPipelining |
Brak równoważnego interfejsu API |
HttpClient nie obsługuje potokowania. |
UseNagleAlgorithm |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
ServicePoint mapowanie metody
| ServicePoint Stary interfejs API | Nowy interfejs API | Uwagi |
|---|---|---|
CloseConnectionGroup |
Brak odpowiednika | Brak obejścia |
SetTcpKeepAlive |
Brak bezpośredniego odpowiednika interfejsu API | Użycie gniazdHttpHandler i ConnectCallback. |
Użycie właściwości HttpClient i HttpRequestMessage
Podczas pracy z klientem HttpClient na platformie .NET masz dostęp do różnych właściwości, które umożliwiają konfigurowanie i dostosowywanie żądań i odpowiedzi HTTP. Zrozumienie tych właściwości może pomóc w jak najlepszym wykorzystaniu HttpClient oraz zapewnieniu, że Twoja aplikacja komunikuje się efektywnie i bezpiecznie z usługami internetowymi.
Przykład: użycie HttpRequestMessage właściwości
Oto przykład, jak używać HttpClient i HttpRequestMessage razem:
var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://example.com"); // Method and RequestUri usage
using 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`.
Przykład: pobieranie identyfikatora URI przekierowanego
Oto przykład pobierania przekierowanego identyfikatora URI (taki sam jak HttpWebRequest.Address):
var client = new HttpClient();
using var response = await client.GetAsync(uri);
var redirectedUri = response.RequestMessage.RequestUri;
Użycie elementów SocketsHttpHandler i ConnectCallback
Właściwość ConnectCallback w programie SocketsHttpHandler umożliwia deweloperom dostosowywanie procesu nawiązywania połączenia TCP. Może to być przydatne w scenariuszach, w których należy kontrolować rozpoznawanie nazw DNS lub stosować określone opcje gniazda w połączeniu. Za pomocą programu ConnectCallbackmożna przechwycić i zmodyfikować proces połączenia, zanim będzie używany przez HttpClientprogram .
Przykład: wiązanie adresu IP z gniazdem
W przypadku starego podejścia przy użyciu metody HttpWebRequestmożna użyć logiki niestandardowej do powiązania określonego adresu IP z gniazdem. Oto jak można osiągnąć podobną funkcjonalność przy użyciu funkcji HttpClient i ConnectCallback:
Stary kod używający 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();
Nowy kod przy użyciu HttpClient i 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);
Przykład: Stosowanie określonych opcji gniazd
Jeśli musisz zastosować określone opcje gniazda, takie jak włączanie zachowania aktywności protokołu TCP, możesz użyć ConnectCallback polecenia , aby skonfigurować gniazdo przed użyciem przez HttpClientprogram . W rzeczywistości ConnectCallback jest bardziej elastyczny do konfigurowania opcji gniazd.
Stary kod używający 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();
Nowy kod przy użyciu HttpClient i 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);
Przykład: włączanie działania okrężnego DNS
Działanie okrężne DNS to technika służąca do dystrybucji ruchu sieciowego między wieloma serwerami przez rotację za pośrednictwem listy adresów IP skojarzonych z jedną nazwą domeny. Pomaga to w równoważeniu obciążenia i poprawie dostępności usług. W przypadku korzystania z programu HttpClientmożna zaimplementować działanie okrężne DNS, ręcznie obsługując rozpoznawanie nazw DNS i obracając się za pośrednictwem adresów IP przy użyciu ConnectCallback właściwości SocketsHttpHandler.
Aby włączyć round-robin DNS za pomocą HttpClient, możesz użyć właściwości ConnectCallback, aby ręcznie rozpoznać wpisy DNS i obracać adresy IP. Oto przykład dla HttpWebRequest i HttpClient:
Stary kod używający HttpWebRequest
ServicePointManager.DnsRefreshTimeout = 60000;
ServicePointManager.EnableDnsRoundRobin = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
W starszym HttpWebRequest interfejsie API włączenie działania okrężnego DNS było proste ze względu na wbudowaną obsługę tej funkcji. Jednak nowszy HttpClient interfejs API nie zapewnia tej samej wbudowanej funkcjonalności. Mimo to można osiągnąć podobne zachowanie, implementując element DnsRoundRobinConnector , który ręcznie obraca się za pośrednictwem adresów IP zwracanych przez rozpoznawanie nazw DNS.
Nowy kod przy użyciu polecenia 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
Aby zapoznać się z implementacją programu DnsRoundRobinConnector, zobacz DnsRoundRobin.cs.
DnsRoundRobinConnector użycie:
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);
}
Przykład: Ustawianie SocketsHttpHandler właściwości
SocketsHttpHandler to zaawansowana i elastyczna procedura obsługi na platformie .NET, która udostępnia zaawansowane opcje konfiguracji do zarządzania połączeniami HTTP. Ustawiając różne właściwości SocketsHttpHandler, można dostosować zachowanie klienta HTTP w celu spełnienia określonych wymagań, takich jak optymalizacja wydajności, zwiększenie bezpieczeństwa i niestandardowa obsługa połączeń.
Oto przykład konfigurowania SocketsHttpHandler za pomocą różnych właściwości i używania go z usługą 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);
Przykład: Zmienianie personifikacjiLevel
Ta funkcja jest specyficzna dla niektórych platform i jest nieco nieaktualna. Jeśli potrzebujesz obejścia problemu, możesz zapoznać się z tą sekcją kodu.
Użycie właściwości związanych z certyfikatem i protokołem TLS w programie HttpClient
Podczas pracy z HttpClientprogramem może być konieczne obsługiwanie certyfikatów klienta w różnych celach, takich jak niestandardowa walidacja certyfikatów serwera lub pobieranie certyfikatu serwera.
HttpClient Udostępnia kilka właściwości i opcji efektywnego zarządzania certyfikatami.
Przykład: Sprawdzanie listy odwołania certyfikatów za pomocą polecenia SocketsHttpHandler
Właściwość CheckCertificateRevocationList w programie SocketsHttpHandler.SslOptions umożliwia deweloperom włączanie lub wyłączanie sprawdzania list odwołania certyfikatów (CRL) podczas uzgadniania protokołu SSL/TLS. Włączenie tej właściwości gwarantuje, że klient sprawdzi, czy certyfikat serwera został odwołany, zwiększając bezpieczeństwo połączenia.
Stary kod używający HttpWebRequest
ServicePointManager.CheckCertificateRevocationList = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Nowy kod przy użyciu polecenia 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);
Przykład: pobieranie certyfikatu
Aby pobrać certyfikat z obiektu RemoteCertificateValidationCallback w HttpClientpliku , możesz użyć ServerCertificateCustomValidationCallback właściwości HttpClientHandler lub SocketsHttpHandler.SslOptions. To wywołanie zwrotne umożliwia inspekcję certyfikatu serwera podczas uzgadniania protokołu SSL/TLS.
Stary kod używający HttpWebRequest
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
X509Certificate? serverCertificate = request.ServicePoint.Certificate;
Nowy kod przy użyciu polecenia 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");
Przykład: Włączanie wzajemnego uwierzytelniania
Wzajemne uwierzytelnianie, nazywane również dwukierunkowym uwierzytelnianiem ssl lub certyfikatem klienta, jest procesem zabezpieczeń, w którym klient i serwer uwierzytelniają się nawzajem. Gwarantuje to, że obie strony są osobami, które twierdzą, zapewniając dodatkową warstwę zabezpieczeń dla poufnej komunikacji. W HttpClientprogramie można włączyć wzajemne uwierzytelnianie, konfigurując certyfikat klienta lub HttpClientHandler i weryfikując SocketsHttpHandler certyfikat serwera.
Aby włączyć wzajemne uwierzytelnianie, wykonaj następujące kroki:
- Załaduj certyfikat klienta.
- Skonfiguruj element
HttpClientHandlerlubSocketsHttpHandler, aby uwzględnić certyfikat klienta. - Skonfiguruj wywołanie zwrotne weryfikacji certyfikatu serwera, jeśli jest wymagana niestandardowa walidacja.
Oto przykład z 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);
Użycie właściwości nagłówka
Nagłówki odgrywają kluczową rolę w komunikacji HTTP, zapewniając podstawowe metadane dotyczące żądania i odpowiedzi. Podczas pracy z platformą HttpClient .NET można ustawić różne właściwości nagłówka i zarządzać nimi, aby kontrolować zachowanie żądań i odpowiedzi HTTP. Zrozumienie sposobu efektywnego korzystania z tych właściwości nagłówka może pomóc w zapewnieniu, że aplikacja komunikuje się wydajnie i bezpiecznie z usługami internetowymi.
Ustawianie nagłówków żądań
Nagłówki żądań są używane do przekazywania dodatkowych informacji do serwera o żądaniu. Typowe przypadki użycia obejmują określanie typu zawartości, ustawianie tokenów uwierzytelniania i dodawanie nagłówków niestandardowych. Nagłówki żądań można ustawić przy użyciu DefaultRequestHeaders właściwości HttpClient lub Headers właściwości HttpRequestMessage.
Przykład: Ustawianie niestandardowych nagłówków żądań
Ustawianie domyślnych niestandardowych nagłówków żądań w programie HttpClient
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Custom-Header", "value");
Ustawianie niestandardowych nagłówków żądań w programie HttpRequestMessage
using var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("Custom-Header", "value");
Przykład: Ustawianie typowych nagłówków żądań
Podczas pracy z platformą HttpRequestMessage .NET ustawienie typowych nagłówków żądań jest niezbędne do dostarczenia dodatkowych informacji na temat wykonywanego żądania. Te nagłówki mogą zawierać tokeny uwierzytelniania i nie tylko. Prawidłowe skonfigurowanie tych nagłówków gwarantuje, że żądania HTTP są prawidłowo przetwarzane przez serwer.
Aby uzyskać kompleksową listę typowych właściwości dostępnych w programie HttpRequestHeaders, zobacz Właściwości.
Aby ustawić typowe nagłówki żądań w pliku HttpRequestMessage, możesz użyć Headers właściwości HttpRequestMessage obiektu . Ta właściwość zapewnia dostęp do HttpRequestHeaders kolekcji, w której można w razie potrzeby dodawać lub modyfikować nagłówki.
Ustawianie typowych domyślnych nagłówków żądań w programie HttpClient
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Ustawianie typowych nagłówków żądań w programie HttpRequestMessage
using System.Net.Http.Headers;
using var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Przykład: Ustawianie nagłówków zawartości
Nagłówki zawartości służą do dostarczania dodatkowych informacji o treści żądania HTTP lub odpowiedzi. Podczas pracy z HttpClient programem .NET można ustawić nagłówki zawartości, aby określić typ nośnika, kodowanie i inne metadane związane z wysyłaną lub odbieraną zawartością. Prawidłowe konfigurowanie nagłówków zawartości gwarantuje, że serwer i klient mogą poprawnie interpretować i przetwarzać zawartość.
var client = new HttpClient();
using 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);
Przykład: Ustaw MaximumErrorResponseLength w HttpClient
Użycie MaximumErrorResponseLength umożliwia deweloperom określenie maksymalnej długości zawartości odpowiedzi na błędy buforowania programu obsługi. Jest to przydatne do kontrolowania ilości danych odczytywanych i przechowywanych w pamięci po odebraniu odpowiedzi o błędzie z serwera. Korzystając z tej techniki, można zapobiec nadmiernemu użyciu pamięci i poprawić wydajność aplikacji podczas obsługi dużych odpowiedzi na błędy.
Istnieje kilka sposobów, aby to zrobić, przeanalizujemy TruncatedReadStream technikę w tym przykładzie:
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();
}
}
}
Przykład użycia :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);
}
Przykład: Stosowanie CachePolicy nagłówków
Ostrzeżenie
HttpClient nie ma wbudowanej logiki do buforowania odpowiedzi. Nie ma obejścia innego niż implementowanie wszystkich buforowania samodzielnie. Po prostu ustawienie nagłówków nie spowoduje buforowania.
Podczas migracji z HttpWebRequest do HttpClientprogramu ważne jest, aby prawidłowo obsługiwać nagłówki związane z pamięcią podręczną, takie jak pragma i cache-control. Te nagłówki kontrolują sposób buforowania i pobierania odpowiedzi, zapewniając, że aplikacja zachowuje się zgodnie z oczekiwaniami w zakresie wydajności i aktualności danych.
W HttpWebRequestprogramie można użyć CachePolicy właściwości , aby ustawić te nagłówki. Jednak w pliku HttpClientnależy ręcznie ustawić te nagłówki na żądanie.
Stary kod używający HttpWebRequest
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
W starszym HttpWebRequest interfejsie API stosowanie CachePolicy było proste ze względu na wbudowaną obsługę tej funkcji. Jednak nowszy HttpClient interfejs API nie zapewnia tej samej wbudowanej funkcjonalności. Mimo to można osiągnąć podobne zachowanie, implementując AddCacheControlHeaders ręcznie dodaj nagłówki powiązane z pamięcią podręczną.
Nowy kod przy użyciu polecenia HttpClient:
public static class CachePolicy
{
public static void AddCacheControlHeaders(HttpRequestMessage request, RequestCachePolicy policy)
Aby zapoznać się z implementacją programu AddCacheControlHeaders, zobacz AddCacheControlHeaders.cs.
AddCacheControlHeaders Zwyczaj:
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);
}
Użycie właściwości buforowania
Podczas migracji z HttpWebRequest do HttpClient ważne jest, aby zrozumieć różnice w sposobie obsługi buforowania tych dwóch interfejsów API.
Stary kod używający HttpWebRequest
W HttpWebRequestsystemie masz bezpośrednią kontrolę nad buforowaniem właściwości za pośrednictwem AllowWriteStreamBuffering właściwości i AllowReadStreamBuffering . Te właściwości włączają lub wyłączają buforowanie danych wysyłanych do serwera i odbieranych z serwera.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowReadStreamBuffering = true; // Default is `false`.
request.AllowWriteStreamBuffering = false; // Default is `true`.
Nowy kod przy użyciu polecenia HttpClient:
W HttpClientsystemie nie ma bezpośrednich odpowiedników AllowWriteStreamBuffering właściwości i AllowReadStreamBuffering .
HttpClient nie buforuje samodzielnie korpusów żądań, zamiast tego delegując odpowiedzialność na użyty HttpContent. Zawartość, taka jak StringContent lub ByteArrayContent, jest już logicznie buforowana w pamięci, podczas gdy użycie StreamContent nie spowoduje buforowania domyślnie. Aby wymusić buforowaną zawartość, możesz wywołać HttpContent.LoadIntoBufferAsync metodę przed wysłaniem żądania. Oto przykład:
HttpClient client = new HttpClient();
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StreamContent(yourStream);
await request.Content.LoadIntoBufferAsync();
using HttpResponseMessage response = await client.SendAsync(request);
Buforowanie HttpClient odczytu jest domyślnie włączone. Aby tego uniknąć, możesz określić flagę HttpCompletionOption.ResponseHeadersRead lub użyć GetStreamAsync pomocnika.
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);