Sdílet prostřednictvím


Průvodce migrací HttpWebRequest na HttpClient

Cílem tohoto článku je vést vývojáře procesem migrace z HttpWebRequest, ServicePointa ServicePointManager do HttpClient. Migrace je nezbytná kvůli zastaralosti starších rozhraní API a mnoha výhod, které HttpClientnabízí , včetně lepšího výkonu, lepší správy prostředků a modernějšího a flexibilnějšího návrhu rozhraní API. Podle kroků popsaných v tomto dokumentu budou vývojáři moci hladce převést své základy kódu a plně využít výhod funkcí poskytovaných HttpClient.

Upozorňující

Migrace z HttpWebRequest, ServicePointa ServicePointManager do HttpClient není jen "pěkné mít" zlepšení výkonu. Je důležité si uvědomit, že výkon stávající WebRequest logiky se při přechodu na .NET (Core) pravděpodobně výrazně sníží. Je to proto WebRequest , že se udržuje jako minimální vrstva kompatibility, což znamená, že nemá mnoho optimalizací, jako je opakované použití připojení v mnoha případech. Přechod na HttpClient je proto nezbytný k zajištění výkonu a správy prostředků vaší aplikace až do moderních standardů.

Migrace z HttpWebRequest do HttpClient

Začněme několika příklady:

Jednoduchý požadavek GET s využitím HttpWebRequest

Tady je příklad, jak může kód vypadat:

HttpWebRequest request = WebRequest.CreateHttp(uri);
using WebResponse response = await request.GetResponseAsync();

Jednoduchý požadavek GET s využitím HttpClient

Tady je příklad, jak může kód vypadat:

HttpClient client = new();
using HttpResponseMessage message = await client.GetAsync(uri);

Jednoduchý požadavek POST s využitím HttpWebRequest

Tady je příklad, jak může kód vypadat:

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();

Jednoduchý požadavek POST s využitím HttpClient

Tady je příklad, jak může kód vypadat:

HttpClient client = new();
using HttpResponseMessage responseMessage = await client.PostAsync(uri, new StringContent("Hello World!"));

Průvodce migrací HttpWebRequest na HttpClient, SocketsHttpHandler

HttpWebRequest Staré rozhraní API Nové rozhraní API Notes
Accept Accept Příklad: Nastavte hlavičky požadavku.
Address RequestUri Příklad: Načíst přesměrovaný identifikátor URI.
AllowAutoRedirect AllowAutoRedirect Příklad: Nastavení vlastností SocketsHttpHandler
AllowReadStreamBuffering Žádné přímé ekvivalentní rozhraní API Použití vlastností ukládání do vyrovnávací paměti
AllowWriteStreamBuffering Žádné přímé ekvivalentní rozhraní API Použití vlastností ukládání do vyrovnávací paměti
AuthenticationLevel Žádné přímé ekvivalentní rozhraní API Příklad: Povolení vzájemného ověřování
AutomaticDecompression AutomaticDecompression Příklad: Nastavení vlastností SocketsHttpHandler
CachePolicy Žádné přímé ekvivalentní rozhraní API Příklad: Použít hlavičky CachePolicy.
ClientCertificates SslOptions.ClientCertificates Použití vlastností souvisejících s certifikáty v HttpClient
Connection Connection Příklad: Nastavte hlavičky požadavku.
ConnectionGroupName Žádné ekvivalentní rozhraní API Žádné alternativní řešení
ContentLength ContentLength Příklad: Nastavení záhlaví obsahu
ContentType ContentType Příklad: Nastavení záhlaví obsahu
ContinueDelegate Žádné ekvivalentní rozhraní API Alternativní řešení neexistuje.
ContinueTimeout Expect100ContinueTimeout Příklad: Nastavte vlastnosti SocketsHttpHandler.
CookieContainer CookieContainer Příklad: Nastavte vlastnosti SocketsHttpHandler.
Credentials Credentials Příklad: Nastavte vlastnosti SocketsHttpHandler.
Date Date Příklad: Nastavte hlavičky požadavku.
DefaultCachePolicy Žádné přímé ekvivalentní rozhraní API Příklad: Použít hlavičky CachePolicy.
DefaultMaximumErrorResponseLength Žádné přímé ekvivalentní rozhraní API Příklad: Nastavení MaximumErrorResponseLength v HttpClient.
DefaultMaximumResponseHeadersLength Žádné ekvivalentní rozhraní API MaxResponseHeadersLength místo toho lze použít.
DefaultWebProxy Žádné ekvivalentní rozhraní API Proxy místo toho lze použít.
Expect Expect Příklad: Nastavte hlavičky požadavku.
HaveResponse Žádné ekvivalentní rozhraní API Implikuje se tím, HttpResponseMessage že má instanci.
Headers Headers Příklad: Nastavte hlavičky požadavku.
Host Host Příklad: Nastavte hlavičky požadavku.
IfModifiedSince IfModifiedSince Příklad: Nastavte hlavičky požadavku.
ImpersonationLevel Žádné přímé ekvivalentní rozhraní API Příklad: Změna zosobněníLevel.
KeepAlive Žádné přímé ekvivalentní rozhraní API Příklad: Nastavte hlavičky požadavku.
MaximumAutomaticRedirections MaxAutomaticRedirections Příklad: Nastavení vlastností SocketsHttpHandler
MaximumResponseHeadersLength MaxResponseHeadersLength Příklad: Nastavení vlastností SocketsHttpHandler
MediaType Žádné přímé ekvivalentní rozhraní API Příklad: Nastavení záhlaví obsahu
Method Method Příklad: Použití vlastností HttpRequestMessage.
Pipelined Žádné ekvivalentní rozhraní API HttpClient nepodporuje pipelining.
PreAuthenticate PreAuthenticate
ProtocolVersion HttpRequestMessage.Version Příklad: Použití vlastností HttpRequestMessage.
Proxy Proxy Příklad: Nastavení vlastností SocketsHttpHandler
ReadWriteTimeout Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.
Referer Referrer Příklad: Nastavte hlavičky požadavku.
RequestUri RequestUri Příklad: Použití vlastností HttpRequestMessage.
SendChunked TransferEncodingChunked Příklad: Nastavte hlavičky požadavku.
ServerCertificateValidationCallback SslOptions.RemoteCertificateValidationCallback Příklad: Nastavení vlastností SocketsHttpHandler
ServicePoint Žádné ekvivalentní rozhraní API ServicePoint není součástí HttpClient.
SupportsCookieContainer Žádné ekvivalentní rozhraní API To je vždy true pro HttpClient.
Timeout Timeout
TransferEncoding TransferEncoding Příklad: Nastavte hlavičky požadavku.
UnsafeAuthenticatedConnectionSharing Žádné ekvivalentní rozhraní API Žádné alternativní řešení
UseDefaultCredentials Žádné přímé ekvivalentní rozhraní API Příklad: Nastavení vlastností SocketsHttpHandler
UserAgent UserAgent Příklad: Nastavte hlavičky požadavku.

Migrace využití ServicePoint(Manager)

Měli byste vědět, že ServicePointManager je statická třída, což znamená, že všechny změny provedené ve svých vlastnostech budou mít globální vliv na všechny nově vytvořené ServicePoint objekty v aplikaci. Když například upravíte vlastnost jako ConnectionLimit nebo Expect100Continue, bude mít vliv na každou novou instanci ServicePointu.

Upozorňující

V moderním rozhraní .NET HttpClient nebere v úvahu žádné konfigurace nastavené na ServicePointManager.

ServicePointManager mapování vlastností

ServicePointManager Staré rozhraní API Nové rozhraní API Notes
CheckCertificateRevocationList SslOptions.CertificateRevocationCheckMode Příklad: Povolení kontroly seznamu CRL pomocí SocketsHttpHandler
DefaultConnectionLimit MaxConnectionsPerServer Příklad: Nastavení vlastností SocketsHttpHandler
DnsRefreshTimeout Žádné ekvivalentní rozhraní API Příklad: Povolení kruhového dotazování Dns
EnableDnsRoundRobin Žádné ekvivalentní rozhraní API Příklad: Povolení kruhového dotazování Dns
EncryptionPolicy SslOptions.EncryptionPolicy Příklad: Nastavení vlastností SocketsHttpHandler
Expect100Continue ExpectContinue Příklad: Nastavte hlavičky požadavku.
MaxServicePointIdleTime PooledConnectionIdleTimeout Příklad: Nastavení vlastností SocketsHttpHandler
MaxServicePoints Žádné ekvivalentní rozhraní API ServicePoint není součástí HttpClient.
ReusePort Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.
SecurityProtocol SslOptions.EnabledSslProtocols Příklad: Nastavení vlastností SocketsHttpHandler
ServerCertificateValidationCallback SslOptions.RemoteCertificateValidationCallback Oba jsou RemoteCertificateValidationCallback
UseNagleAlgorithm Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.

Upozorňující

V moderním .NET jsou výchozí hodnoty pro UseNagleAlgorithm vlastnosti a Expect100Continue vlastnosti nastaveny na false. Tyto hodnoty byly true ve výchozím nastavení v rozhraní .NET Framework.

ServicePointManager mapování metod

ServicePointManager Staré rozhraní API Nové rozhraní API Notes
FindServicePoint Žádné ekvivalentní rozhraní API Žádné alternativní řešení
SetTcpKeepAlive Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.

ServicePoint mapování vlastností

ServicePoint Staré rozhraní API Nové rozhraní API Notes
Address HttpRequestMessage.RequestUri Toto je identifikátor URI požadavku, tyto informace najdete v části HttpRequestMessage.
BindIPEndPointDelegate Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.
Certificate Žádné přímé ekvivalentní rozhraní API Tyto informace lze načíst z RemoteCertificateValidationCallback. Příklad: Načtení certifikátu
ClientCertificate Žádné ekvivalentní rozhraní API Příklad: Povolení vzájemného ověřování
ConnectionLeaseTimeout SocketsHttpHandler.PooledConnectionLifetime Ekvivalentní nastavení v HttpClient
ConnectionLimit MaxConnectionsPerServer Příklad: Nastavení vlastností SocketsHttpHandler
ConnectionName Žádné ekvivalentní rozhraní API Žádné alternativní řešení
CurrentConnections Žádné ekvivalentní rozhraní API Viz Telemetrie sítí v .NET.
Expect100Continue ExpectContinue Příklad: Nastavte hlavičky požadavku.
IdleSince Žádné ekvivalentní rozhraní API Žádné alternativní řešení
MaxIdleTime PooledConnectionIdleTimeout Příklad: Nastavení vlastností SocketsHttpHandler
ProtocolVersion HttpRequestMessage.Version Příklad: Použití vlastností HttpRequestMessage.
ReceiveBufferSize Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.
SupportsPipelining Žádné ekvivalentní rozhraní API HttpClient nepodporuje pipelining.
UseNagleAlgorithm Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.

ServicePoint mapování metod

ServicePoint Staré rozhraní API Nové rozhraní API Notes
CloseConnectionGroup Žádný ekvivalent Žádné alternativní řešení
SetTcpKeepAlive Žádné přímé ekvivalentní rozhraní API Použití SocketsHttpHandler a ConnectCallback.

Použití vlastností HttpClient a HttpRequestMessage

Při práci s HttpClient v .NET máte přístup k nejrůznějším vlastnostem, které umožňují konfigurovat a přizpůsobovat požadavky a odpovědi HTTP. Porozumění těmto vlastnostem vám může pomoct maximálně využít HttpClient a zajistit efektivní a bezpečnou komunikaci vaší aplikace s webovými službami.

Příklad: Použití vlastností HttpRequestMessage

Tady je příklad, jak společně používat HttpClient a 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`.

Příklad: Fetch redirected URI

Tady je příklad, jak načíst přesměrovaný identifikátor URI (stejný jako HttpWebRequest.Address):

var client = new HttpClient();
using var response = await client.GetAsync(uri);
var redirectedUri = response.RequestMessage.RequestUri;

Použití SocketsHttpHandler a ConnectCallback

Tato ConnectCallback vlastnost SocketsHttpHandler umožňuje vývojářům přizpůsobit proces vytvoření připojení TCP. To může být užitečné pro scénáře, kdy potřebujete řídit překlad DNS nebo použít konkrétní možnosti soketu na připojení. Pomocí ConnectCallback, můžete zachytit a upravit proces připojení před jeho použitím HttpClient.

Příklad: Vytvoření vazby IP adresy k soketu

Ve starém přístupu, který používáte HttpWebRequest, jste možná použili vlastní logiku k vytvoření vazby konkrétní IP adresy na soket. Tady je postup, jak dosáhnout podobných funkcí pomocí HttpClient a ConnectCallback:

Starý kód používající 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();

Nový kód používající HttpClient a 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);

Příklad: Použití konkrétních možností soketů

Pokud potřebujete použít specifické možnosti soketu, jako je povolení udržování protokolu TCP, můžete použít ConnectCallback ke konfiguraci soketu před jeho použitím HttpClient. Ve skutečnosti ConnectCallback je flexibilnější konfigurace možností soketů.

Starý kód používající 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();

Nový kód používající HttpClient a 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);

Příklad: Povolení kruhového dotazování DNS

Kruhové dotazování DNS je technika, která se používá k distribuci síťového provozu mezi více serverů otočením seznamu IP adres přidružených k jednomu názvu domény. To pomáhá při vyrovnávání zatížení a zlepšení dostupnosti služeb. Pokud používáte HttpClient, můžete implementovat DNS Round Robin ručním zpracováním překladu DNS a rotací přes IP adresy pomocí ConnectCallback vlastnost SocketsHttpHandler.

Chcete-li povolit dns Round Robin s HttpClient, můžete použít ConnectCallback vlastnost ručně přeložit záznamy DNS a otočit přes IP adresy. Tady je příklad:HttpWebRequest HttpClient

Starý kód používající HttpWebRequest:

ServicePointManager.DnsRefreshTimeout = 60000;
ServicePointManager.EnableDnsRoundRobin = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();

Ve starším HttpWebRequest rozhraní API bylo povolení kruhového dotazování DNS jednoduché kvůli integrované podpoře této funkce. Novější HttpClient rozhraní API ale neposkytuje stejné integrované funkce. Navzdory tomu můžete dosáhnout podobného chování implementací DnsRoundRobinConnector , která se ručně otočí přes IP adresy vrácené překladem DNS.

Nový kód pomocí 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

Implementace najdete DnsRoundRobinConnector tady.

DnsRoundRobinConnector Zvyk:

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);
}

Příklad: Nastavení vlastností SocketsHttpHandler

SocketsHttpHandler je výkonná a flexibilní obslužná rutina v .NET, která poskytuje pokročilé možnosti konfigurace pro správu připojení HTTP. Nastavením různých vlastností SocketsHttpHandler můžete doladit chování klienta HTTP tak, aby splňovalo konkrétní požadavky, jako je optimalizace výkonu, vylepšení zabezpečení a vlastní zpracování připojení.

Tady je příklad konfigurace SocketsHttpHandler s různými vlastnostmi a jeho použití s 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);

Příklad: Změna zosobněníLevel

Tato funkce je specifická pro určité platformy a je poněkud zastaralá. Pokud potřebujete alternativní řešení, můžete se podívat na tuto část kódu.

Při práci s klienty HttpClientmůže být potřeba zpracovávat klientské certifikáty pro různé účely, například vlastní ověření certifikátů serveru nebo načtení certifikátu serveru. HttpClient poskytuje několik vlastností a možností efektivní správy certifikátů.

Příklad: Kontrola seznamu odvolaných certifikátů pomocí SocketsHttpHandler

Tato CheckCertificateRevocationList vlastnost SocketsHttpHandler.SslOptions umožňuje vývojářům povolit nebo zakázat kontrolu seznamů odvolaných certifikátů (CRL) během metody handshake protokolu SSL/TLS. Povolením této vlastnosti zajistíte, že klient ověří, jestli byl certifikát serveru odvolán, což zvyšuje zabezpečení připojení.

Starý kód používající HttpWebRequest:

ServicePointManager.CheckCertificateRevocationList = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();

Nový kód pomocí 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);

Příklad: Načtení certifikátu

Chcete-li načíst certifikát z objektu RemoteCertificateValidationCallback HttpClientin , můžete použít ServerCertificateCustomValidationCallback vlastnost HttpClientHandler nebo SocketsHttpHandler.SslOptions. Toto zpětné volání umožňuje zkontrolovat certifikát serveru během metody handshake PROTOKOLU SSL/TLS.

Starý kód používající HttpWebRequest:

HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
X509Certificate? serverCertificate = request.ServicePoint.Certificate;

Nový kód pomocí 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");

Příklad: Povolení vzájemného ověřování

Vzájemné ověřování, označované také jako obousměrné ověřování SSL nebo klientského certifikátu, je proces zabezpečení, ve kterém se klient i server vzájemně ověřují. Tím zajistíte, že obě strany budou tím, kdo tvrdí, že jsou, a poskytují další vrstvu zabezpečení pro citlivou komunikaci. V HttpClientsystému můžete povolit vzájemné ověřování tak HttpClientHandler , že nakonfigurujete nebo SocketsHttpHandler zahrnete klientský certifikát a ověříte certifikát serveru.

Chcete-li povolit vzájemné ověřování, postupujte takto:

  • Načtěte klientský certifikát.
  • Nakonfigurujte HttpClientHandler nebo SocketsHttpHandler tak, aby zahrnoval klientský certifikát.
  • Pokud je potřeba vlastní ověření, nastavte zpětné volání ověření certifikátu serveru.

Tady je příklad použití 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);

Použití vlastností záhlaví

Hlavičky hrají zásadní roli při komunikaci HTTP a poskytují základní metadata o požadavku a odpovědi. Při práci s rozhraním HttpClient .NET můžete nastavit a spravovat různé vlastnosti hlaviček, abyste mohli řídit chování požadavků a odpovědí HTTP. Když pochopíte, jak efektivně používat tyto vlastnosti hlaviček, pomůže vám to zajistit efektivní a bezpečnou komunikaci vaší aplikace s webovými službami.

Nastavení hlaviček požadavků

Hlavičky požadavku slouží k poskytnutí dalších informací serveru o provedené žádosti. Mezi běžné případy použití patří určení typu obsahu, nastavení ověřovacích tokenů a přidání vlastních hlaviček. Hlavičky požadavku můžete nastavit pomocí DefaultRequestHeaders vlastnosti HttpClient nebo vlastnosti Headers objektu HttpRequestMessage.

Příklad: Nastavení hlaviček vlastních požadavků

Nastavení výchozích hlaviček vlastních požadavků v HttpClient

var client = new HttpClient();
client.DefaultRequestHeaders.Add("Custom-Header", "value");

Nastavení hlaviček vlastních požadavků v HttpRequestMessage

var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("Custom-Header", "value");

Příklad: Nastavení běžných hlaviček požadavků

Při práci s rozhraním HttpRequestMessage .NET je nastavení běžných hlaviček požadavků nezbytné pro poskytnutí dalších informací serveru o provedené žádosti. Tyto hlavičky můžou zahrnovat ověřovací tokeny a další. Správná konfigurace těchto hlaviček zajistí, že server správně zpracuje vaše požadavky HTTP. Úplný seznam běžných vlastností dostupných v HttpRequestHeadersčásti Vlastnosti.

Chcete-li nastavit běžné hlavičky požadavku v HttpRequestMessage, můžete použít Headers vlastnost objektu HttpRequestMessage . Tato vlastnost poskytuje přístup k kolekci HttpRequestHeaders , kde můžete podle potřeby přidávat nebo upravovat záhlaví.

Nastavení běžných výchozích hlaviček požadavků v HttpClient

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");

Nastavení běžných hlaviček požadavků v HttpRequestMessage

using System.Net.Http.Headers;

var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "token");

Příklad: Nastavení záhlaví obsahu

Hlavičky obsahu slouží k poskytnutí dalších informací o textu požadavku nebo odpovědi HTTP. Při práci s rozhraním HttpClient .NET můžete nastavit hlavičky obsahu tak, aby určily typ média, kódování a další metadata související s odesílaným nebo přijatým obsahem. Správná konfigurace hlaviček obsahu zajišťuje, aby server a klient mohli obsah správně interpretovat a zpracovávat.

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);

Příklad: Nastavení MaximumErrorResponseLength v HttpClient

Použití MaximumErrorResponseLength umožňuje vývojářům určit maximální délku obsahu odpovědi na chybu, který obslužná rutina uloží do vyrovnávací paměti. To je užitečné pro řízení množství dat, která se čtou a ukládají v paměti, když se ze serveru obdrží chybová odpověď. Pomocí této techniky můžete zabránit nadměrnému využití paměti a zlepšit výkon aplikace při zpracování velkých chybových odpovědí.

Existuje několik způsobů, jak to udělat, podíváme TruncatedReadStream se na techniku v tomto příkladu:

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();
        }
    }
}

Příklad použití 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);
}

Příklad: Použití hlaviček CachePolicy

Upozorňující

HttpClient nemá integrovanou logiku pro ukládání odpovědí do mezipaměti. Neexistuje žádné alternativní řešení než implementace veškeré mezipaměti sami. Jednoduše nastavíte hlavičky, které nedosáhnou ukládání do mezipaměti.

Při migraci z HttpWebRequest do HttpClientje důležité správně zpracovávat hlavičky související s mezipamětí, jako pragma cache-controlje a . Tyto hlavičky určují, jak se odpovědi ukládají do mezipaměti a načítají, a zajišťují, aby se vaše aplikace chovala podle očekávání z hlediska výkonu a aktuálnosti dat.

V HttpWebRequest, můžete použít CachePolicy vlastnost k nastavení těchto hlaviček. V případě požadavku HttpClientvšak musíte tyto hlavičky nastavit ručně.

Starý kód používající HttpWebRequest:

HttpWebRequest request = WebRequest.CreateHttp(uri);
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();

Ve starším HttpWebRequest rozhraní API bylo použití CachePolicy jednoduché kvůli integrované podpoře této funkce. Novější HttpClient rozhraní API ale neposkytuje stejné integrované funkce. Navzdory tomu můžete dosáhnout podobného chování implementací AddCacheControlHeaders ručně přidávaných hlaviček souvisejících s mezipamětí.

Nový kód pomocí HttpClient:

public static class CachePolicy
{
    public static void AddCacheControlHeaders(HttpRequestMessage request, RequestCachePolicy policy)

Implementace najdete AddCacheControlHeaders tady.

AddCacheControlHeaders Zvyk:

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);
}

Použití vlastností ukládání do vyrovnávací paměti

Při migraci z HttpWebRequest na HttpClient, je důležité pochopit rozdíly v tom, jak tyto dvě rozhraní API zpracovávají ukládání do vyrovnávací paměti.

Starý kód používající HttpWebRequest:

V HttpWebRequestaplikaci máte přímou kontrolu nad ukládáním vlastností do vyrovnávací paměti prostřednictvím AllowWriteStreamBuffering vlastností a AllowReadStreamBuffering vlastností. Tyto vlastnosti umožňují nebo zakazují ukládání dat do vyrovnávací paměti odesílaných na server a jejich příjem ze serveru.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowReadStreamBuffering = true; // Default is `false`.
request.AllowWriteStreamBuffering = false; // Default is `true`.

Nový kód pomocí HttpClient:

V HttpClient, neexistují žádné přímé ekvivalenty AllowWriteStreamBuffering a AllowReadStreamBuffering vlastnosti.

HttpClient sama o sobě neukládá do vyrovnávací paměti těla požadavků, místo toho deleguje odpovědnost na použitou HttpContent . Obsah, jako StringContent je nebo ByteArrayContent jsou logicky již v paměti, zatímco použití StreamContent ve výchozím nastavení nebude mít žádnou vyrovnávací paměť. Pokud chcete vynutit ukládání obsahu do vyrovnávací paměti, můžete před odesláním požadavku volat HttpContent.LoadIntoBufferAsync . Tady je příklad:

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);

Ukládání HttpClient do vyrovnávací paměti pro čtení je ve výchozím nastavení povolené. Abyste se tomu vyhnuli, můžete určit HttpCompletionOption.ResponseHeadersRead příznak nebo použít pomocnou rutinu 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);