Przewodnik migracji httpWebRequest do klienta HttpClient
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 HttpWebRequest
elementu , ServicePoint
i 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 to HttpClient, SocketsHttpHandler migration guide (Przewodnik migracji httpWebRequest do klienta HttpClient, SocketsHttpHandler)
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ń. |
Migrowanie użycia programu ServicePoint(Manager)
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 ona wpływ na każde nowe wystąpienie programu ServicePoint.
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 największym zapewnieniu, że aplikacja komunikuje się wydajnie i bezpiecznie z usługami internetowymi.
Przykład: użycie właściwości HttpRequestMessage
Oto przykład użycia elementów HttpClient i HttpRequestMessage razem:
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`.
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 gniazdHttpHandler 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 ConnectCallback
można przechwycić i zmodyfikować proces połączenia, zanim będzie używany przez HttpClient
program .
Przykład: wiązanie adresu IP z gniazdem
W przypadku starego podejścia przy użyciu metody HttpWebRequest
moż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 przy użyciu polecenia 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 i 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);
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 HttpClient
program . W rzeczywistości ConnectCallback
jest bardziej elastyczny do konfigurowania opcji gniazd.
Stary kod przy użyciu polecenia 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 i 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);
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 klienta HttpClient moż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 właściwości ConnectCallback socketsHttpHandler.
Aby włączyć działanie okrężne DNS za pomocą klienta HttpClient, możesz użyć właściwości ConnectCallback, aby ręcznie rozpoznać wpisy DNS i obracać się za pośrednictwem adresów IP. Oto przykład dla HttpWebRequest
i HttpClient
:
Stary kod przy użyciu polecenia 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
Implementację DnsRoundRobinConnector
można znaleźć tutaj.
DnsRoundRobinConnector
Zwyczaj:
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 właściwości SocketsHttpHandler
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, ulepszenia zabezpieczeń i niestandardowa obsługa połączeń.
Oto przykład konfigurowania programu SocketsHttpHandler z różnymi właściwościami i używania go z klientem 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 certyfikatu i protokołu TLS w programie HttpClient
Podczas pracy z HttpClient
programem 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ą programu 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 przy użyciu polecenia 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 HttpClient
pliku , 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 przy użyciu polecenia 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 HttpClient
programie można włączyć wzajemne uwierzytelnianie, konfigurując certyfikat klienta lub SocketsHttpHandler
i weryfikując HttpClientHandler
certyfikat serwera.
Aby włączyć wzajemne uwierzytelnianie, wykonaj następujące kroki:
- Załaduj certyfikat klienta.
- Skonfiguruj program HttpClientHandler lub SocketsHttpHandler, aby uwzględnić certyfikat klienta.
- Skonfiguruj wywołanie zwrotne weryfikacji certyfikatu serwera, jeśli jest wymagana niestandardowa walidacja.
Oto przykład użycia programu 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 właściwości Headers obiektu 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 httpRequestMessage
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 httpRequestMessage
using System.Net.Http.Headers;
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();
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 wartość MaximumErrorResponseLength w obiekcie 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 nagłówków CachePolicy
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 HttpClient
programu 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 HttpWebRequest
programie można użyć CachePolicy
właściwości , aby ustawić te nagłówki. Jednak w pliku HttpClient
należy ręcznie ustawić te nagłówki na żądanie.
Stary kod przy użyciu polecenia 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)
Implementację AddCacheControlHeaders
można znaleźć tutaj.
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 usługi HttpWebRequest do HttpClient
usługi należy zrozumieć różnice w sposobie obsługi buforowania tych dwóch interfejsów API.
Stary kod przy użyciu polecenia HttpWebRequest
:
W HttpWebRequest
systemie 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 HttpClient
systemie nie ma bezpośrednich odpowiedników AllowWriteStreamBuffering
właściwości i AllowReadStreamBuffering
.
Obiekt HttpClient nie buforuje własnych treści żądań, zamiast tego deleguje odpowiedzialność za HttpContent
użyte elementy. Zawartość, na przykład StringContent
lub ByteArrayContent
są już logicznie buforowane w pamięci, podczas gdy użycie StreamContent
nie spowoduje domyślnego buforowania. Aby wymusić buforowaną zawartość, możesz wywołać HttpContent.LoadIntoBufferAsync
metodę przed wysłaniem żądania. Oto przykład:
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);
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);