Guia de migração de HttpWebRequest para HttpClient
Este artigo tem como objetivo orientar os desenvolvedores através do processo de migração de HttpWebRequest, ServicePointe ServicePointManager para HttpClient. A migração é necessária devido à obsolescência das APIs mais antigas e aos inúmeros benefícios oferecidos pela HttpClient, incluindo melhor desempenho, melhor gerenciamento de recursos e um design de API mais moderno e flexível. Seguindo as etapas descritas neste documento, os desenvolvedores poderão fazer a transição de suas bases de código sem problemas e aproveitar ao máximo os recursos fornecidos pelo HttpClient.
Aviso
Migrar de , ServicePoint
e ServicePointManager
para HttpClient
não é apenas uma melhoria de HttpWebRequest
desempenho "agradável de ter". É crucial entender que o desempenho da lógica existente WebRequest
provavelmente se degradará significativamente quando você mudar para o .NET (Core). Isso porque WebRequest
é mantido como uma camada mínima de compatibilidade, o que significa que carece de muitas otimizações, como a reutilização de conexão em vários casos. Portanto, a transição para HttpClient
é essencial para garantir que o desempenho do seu aplicativo e o gerenciamento de recursos estejam de acordo com os padrões modernos.
Migrar de HttpWebRequest para HttpClient
Comecemos por alguns exemplos:
Solicitação GET simples usando HttpWebRequest
Aqui está um exemplo de como o código pode parecer:
HttpWebRequest request = WebRequest.CreateHttp(uri);
using WebResponse response = await request.GetResponseAsync();
Solicitação GET simples usando HttpClient
Aqui está um exemplo de como o código pode parecer:
HttpClient client = new();
using HttpResponseMessage message = await client.GetAsync(uri);
Solicitação POST simples usando HttpWebRequest
Aqui está um exemplo de como o código pode parecer:
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();
Solicitação POST simples usando HttpClient
Aqui está um exemplo de como o código pode parecer:
HttpClient client = new();
using HttpResponseMessage responseMessage = await client.PostAsync(uri, new StringContent("Hello World!"));
HttpWebRequest para HttpClient, guia de migração SocketsHttpHandler
HttpWebRequest API antiga | Nova API | Notas |
---|---|---|
Accept |
Accept | Exemplo: Definir cabeçalhos de solicitação. |
Address |
RequestUri | Exemplo: Buscar URI redirecionado. |
AllowAutoRedirect |
AllowAutoRedirect | Exemplo: Definindo propriedades SocketsHttpHandler. |
AllowReadStreamBuffering |
Nenhuma API equivalente direta | Uso de propriedades de buffer. |
AllowWriteStreamBuffering |
Nenhuma API equivalente direta | Uso de propriedades de buffer. |
AuthenticationLevel |
Nenhuma API equivalente direta | Exemplo: Habilitando a autenticação mútua. |
AutomaticDecompression |
AutomaticDecompression | Exemplo: Definindo propriedades SocketsHttpHandler. |
CachePolicy |
Nenhuma API equivalente direta | Exemplo: Aplicar cabeçalhos CachePolicy. |
ClientCertificates |
SslOptions.ClientCertificates | Uso de propriedades relacionadas ao certificado em HttpClient. |
Connection |
Connection | Exemplo: Definir cabeçalhos de solicitação. |
ConnectionGroupName |
Nenhuma API equivalente | Sem solução alternativa |
ContentLength |
ContentLength | Exemplo: definir cabeçalhos de conteúdo. |
ContentType |
ContentType | Exemplo: definir cabeçalhos de conteúdo. |
ContinueDelegate |
Nenhuma API equivalente | Nenhuma solução alternativa. |
ContinueTimeout |
Expect100ContinueTimeout | Exemplo: Definir propriedades SocketsHttpHandler. |
CookieContainer |
CookieContainer | Exemplo: Definir propriedades SocketsHttpHandler. |
Credentials |
Credentials | Exemplo: Definir propriedades SocketsHttpHandler. |
Date |
Date | Exemplo: Definir cabeçalhos de solicitação. |
DefaultCachePolicy |
Nenhuma API equivalente direta | Exemplo: Aplicar cabeçalhos CachePolicy. |
DefaultMaximumErrorResponseLength |
Nenhuma API equivalente direta | Exemplo: Defina MaximumErrorResponseLength em HttpClient. |
DefaultMaximumResponseHeadersLength |
Nenhuma API equivalente | MaxResponseHeadersLength pode ser usado em vez disso. |
DefaultWebProxy |
Nenhuma API equivalente | Proxy pode ser usado em vez disso. |
Expect |
Expect | Exemplo: Definir cabeçalhos de solicitação. |
HaveResponse |
Nenhuma API equivalente | Implícito por ter uma HttpResponseMessage instância. |
Headers |
Headers | Exemplo: Definir cabeçalhos de solicitação. |
Host |
Host | Exemplo: Definir cabeçalhos de solicitação. |
IfModifiedSince |
IfModifiedSince | Exemplo: Definir cabeçalhos de solicitação. |
ImpersonationLevel |
Nenhuma API equivalente direta | Exemplo: Change ImpersonationLevel. |
KeepAlive |
Nenhuma API equivalente direta | Exemplo: Definir cabeçalhos de solicitação. |
MaximumAutomaticRedirections |
MaxAutomaticRedirections | Exemplo: Definindo propriedades SocketsHttpHandler. |
MaximumResponseHeadersLength |
MaxResponseHeadersLength | Exemplo: Definindo propriedades SocketsHttpHandler. |
MediaType |
Nenhuma API equivalente direta | Exemplo: definir cabeçalhos de conteúdo. |
Method |
Method | Exemplo: Uso de propriedades HttpRequestMessage. |
Pipelined |
Nenhuma API equivalente | HttpClient não suporta pipelining. |
PreAuthenticate |
PreAuthenticate | |
ProtocolVersion |
HttpRequestMessage.Version |
Exemplo: Uso de propriedades HttpRequestMessage. |
Proxy |
Proxy | Exemplo: Definindo propriedades SocketsHttpHandler. |
ReadWriteTimeout |
Nenhuma API equivalente direta | Uso de SocketsHttpHandler e ConnectCallback. |
Referer |
Referrer | Exemplo: Definir cabeçalhos de solicitação. |
RequestUri |
RequestUri | Exemplo: Uso de propriedades HttpRequestMessage. |
SendChunked |
TransferEncodingChunked | Exemplo: Definir cabeçalhos de solicitação. |
ServerCertificateValidationCallback |
SslOptions.RemoteCertificateValidationCallback | Exemplo: Definindo propriedades SocketsHttpHandler. |
ServicePoint |
Nenhuma API equivalente | ServicePoint não faz parte do HttpClient . |
SupportsCookieContainer |
Nenhuma API equivalente | Isto é sempre true para HttpClient . |
Timeout |
Timeout | |
TransferEncoding |
TransferEncoding | Exemplo: Definir cabeçalhos de solicitação. |
UnsafeAuthenticatedConnectionSharing |
Nenhuma API equivalente | Sem solução alternativa |
UseDefaultCredentials |
Nenhuma API equivalente direta | Exemplo: Definindo propriedades SocketsHttpHandler. |
UserAgent |
UserAgent | Exemplo: Definir cabeçalhos de solicitação. |
Migrar o uso do ServicePoint(Manager)
Você deve estar ciente de que ServicePointManager
é uma classe estática, o que significa que quaisquer alterações feitas em suas propriedades terão um efeito global em todos os objetos recém-criados ServicePoint
dentro do aplicativo. Por exemplo, quando você modifica uma propriedade como ConnectionLimit
ou Expect100Continue
, isso afeta cada nova instância do ServicePoint.
Aviso
No .NET moderno, HttpClient
não leva em conta quaisquer configurações definidas em ServicePointManager
.
ServicePointManager Mapeamento de propriedades
Aviso
No .NET moderno, os valores padrão para as UseNagleAlgorithm
propriedades e Expect100Continue
são definidos como false
. Esses valores eram true
por padrão no .NET Framework.
ServicePointManager mapeamento de método
ServicePointManager API antiga | Nova API | Notas |
---|---|---|
FindServicePoint |
Nenhuma API equivalente | Sem solução alternativa |
SetTcpKeepAlive |
Nenhuma API equivalente direta | Uso de SocketsHttpHandler e ConnectCallback. |
ServicePoint Mapeamento de propriedades
ServicePoint API antiga | Nova API | Notas |
---|---|---|
Address |
HttpRequestMessage.RequestUri |
Esta é a solicitação uri, esta informação pode ser encontrada em HttpRequestMessage . |
BindIPEndPointDelegate |
Nenhuma API equivalente direta | Uso de SocketsHttpHandler e ConnectCallback. |
Certificate |
Nenhuma API equivalente direta | Essas informações podem ser obtidas em RemoteCertificateValidationCallback . Exemplo: Buscar certificado. |
ClientCertificate |
Nenhuma API equivalente | Exemplo: Habilitando a autenticação mútua. |
ConnectionLeaseTimeout |
SocketsHttpHandler.PooledConnectionLifetime |
Configuração equivalente em HttpClient |
ConnectionLimit |
MaxConnectionsPerServer | Exemplo: Definindo propriedades SocketsHttpHandler. |
ConnectionName |
Nenhuma API equivalente | Sem solução alternativa |
CurrentConnections |
Nenhuma API equivalente | Consulte Telemetria de rede no .NET. |
Expect100Continue |
ExpectContinue | Exemplo: Definir cabeçalhos de solicitação. |
IdleSince |
Nenhuma API equivalente | Sem solução alternativa |
MaxIdleTime |
PooledConnectionIdleTimeout | Exemplo: Definindo propriedades SocketsHttpHandler. |
ProtocolVersion |
HttpRequestMessage.Version |
Exemplo: Uso de propriedades HttpRequestMessage. |
ReceiveBufferSize |
Nenhuma API equivalente direta | Uso de SocketsHttpHandler e ConnectCallback. |
SupportsPipelining |
Nenhuma API equivalente | HttpClient não suporta pipelining. |
UseNagleAlgorithm |
Nenhuma API equivalente direta | Uso de SocketsHttpHandler e ConnectCallback. |
ServicePoint mapeamento de método
ServicePoint API antiga | Nova API | Notas |
---|---|---|
CloseConnectionGroup |
Sem equivalente | Sem solução alternativa |
SetTcpKeepAlive |
Nenhuma API equivalente direta | Uso de SocketsHttpHandler e ConnectCallback. |
Uso das propriedades HttpClient e HttpRequestMessage
Ao trabalhar com HttpClient no .NET, você tem acesso a uma variedade de propriedades que permitem configurar e personalizar solicitações e respostas HTTP. Compreender essas propriedades pode ajudá-lo a aproveitar ao máximo o HttpClient e garantir que seu aplicativo se comunique de forma eficiente e segura com serviços da Web.
Exemplo: Uso de propriedades HttpRequestMessage
Aqui está um exemplo de como usar HttpClient e HttpRequestMessage juntos:
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`.
Exemplo: Buscar URI redirecionado
Aqui está um exemplo de como buscar URI redirecionado (o mesmo que HttpWebRequest.Address
):
var client = new HttpClient();
using var response = await client.GetAsync(uri);
var redirectedUri = response.RequestMessage.RequestUri;
Uso de SocketsHttpHandler e ConnectCallback
A ConnectCallback
propriedade in SocketsHttpHandler
permite que os desenvolvedores personalizem o processo de estabelecimento de uma conexão TCP. Isso pode ser útil para cenários em que você precisa controlar a resolução DNS ou aplicar opções de soquete específicas na conexão. ConnectCallback
Usando o , você pode intercetar e modificar o processo de conexão antes que ele seja usado pelo HttpClient
.
Exemplo: Vincular endereço IP ao soquete
Na abordagem antiga usando HttpWebRequest
, você pode ter usado lógica personalizada para vincular um endereço IP específico a um soquete. Veja como você pode obter funcionalidade semelhante usando HttpClient
e ConnectCallback
:
Código antigo usando 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();
Novo código usando HttpClient
e 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);
Exemplo: Aplicar opções de soquete específicas
Se você precisar aplicar opções específicas de soquete, como habilitar o TCP keep-alive, poderá usar ConnectCallback
para configurar o soquete antes que ele seja usado pelo HttpClient
. Na verdade, ConnectCallback
é mais flexível para configurar opções de soquete.
Código antigo usando 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();
Novo código usando HttpClient
e 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);
Exemplo: Ativar round robin DNS
DNS Round Robin é uma técnica usada para distribuir o tráfego de rede entre vários servidores, girando através de uma lista de endereços IP associados a um único nome de domínio. Isso ajuda no balanceamento de carga e na melhoria da disponibilidade dos serviços. Ao usar HttpClient, você pode implementar o DNS Round Robin manipulando manualmente a resolução DNS e girando pelos endereços IP usando a propriedade ConnectCallback de SocketsHttpHandler.
Para habilitar o DNS Round Robin com HttpClient, você pode usar a propriedade ConnectCallback para resolver manualmente as entradas DNS e girar pelos endereços IP. Aqui está um exemplo para HttpWebRequest
e HttpClient
:
Código antigo usando HttpWebRequest
:
ServicePointManager.DnsRefreshTimeout = 60000;
ServicePointManager.EnableDnsRoundRobin = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Na API mais antiga HttpWebRequest
, habilitar o DNS Round Robin era simples devido ao seu suporte interno para esse recurso. No entanto, a API mais recente HttpClient
não fornece a mesma funcionalidade interna. Apesar disso, você pode obter um comportamento semelhante implementando um DnsRoundRobinConnector
que gira manualmente através dos endereços IP retornados pela resolução DNS.
Novo código usando 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
Você pode encontrar a implementação de DnsRoundRobinConnector
aqui.
DnsRoundRobinConnector
Utilização:
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);
}
Exemplo: Definir propriedades SocketsHttpHandler
SocketsHttpHandler é um manipulador poderoso e flexível no .NET que fornece opções de configuração avançadas para gerenciar conexões HTTP. Ao definir várias propriedades de SocketsHttpHandler, você pode ajustar o comportamento do seu cliente HTTP para atender a requisitos específicos, como otimização de desempenho, aprimoramentos de segurança e manipulação de conexão personalizada.
Aqui está um exemplo de como configurar SocketsHttpHandler com várias propriedades e usá-lo com 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);
Exemplo: Change ImpersonationLevel
Esta funcionalidade é específica para determinadas plataformas e está um pouco desatualizada. Se você precisar de uma solução alternativa, você pode consultar esta seção do código.
Uso de propriedades relacionadas a Certificado e TLS em HttpClient
Ao trabalhar com HttpClient
o , talvez seja necessário manipular certificados de cliente para vários fins, como validação personalizada de certificados de servidor ou busca de certificado de servidor. HttpClient
Fornece várias propriedades e opções para gerenciar certificados de forma eficaz.
Exemplo: Verifique a lista de revogação de certificados com SocketsHttpHandler
A CheckCertificateRevocationList
propriedade in SocketsHttpHandler.SslOptions
permite que os desenvolvedores habilitem ou desabilitem a verificação de listas de revogação de certificados (CRL) durante o handshake SSL/TLS. Habilitar essa propriedade garante que o cliente verifique se o certificado do servidor foi revogado, aumentando a segurança da conexão.
Código antigo usando HttpWebRequest
:
ServicePointManager.CheckCertificateRevocationList = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Novo código usando 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);
Exemplo: Buscar certificado
Para buscar o certificado do RemoteCertificateValidationCallback
in HttpClient
, você pode usar a ServerCertificateCustomValidationCallback
propriedade de HttpClientHandler
ou SocketsHttpHandler.SslOptions
. Esse retorno de chamada permite que você inspecione o certificado do servidor durante o handshake SSL/TLS.
Código antigo usando HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
X509Certificate? serverCertificate = request.ServicePoint.Certificate;
Novo código usando 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");
Exemplo: Habilitar autenticação mútua
A autenticação mútua, também conhecida como SSL bidirecional ou autenticação de certificado de cliente, é um processo de segurança no qual o cliente e o servidor se autenticam. Isso garante que ambas as partes sejam quem afirmam ser, fornecendo uma camada adicional de segurança para comunicações confidenciais. No HttpClient
, você pode habilitar a autenticação mútua configurando o HttpClientHandler
ou SocketsHttpHandler
para incluir o certificado do cliente e validar o certificado do servidor.
Para ativar a autenticação mútua, siga estes passos:
- Carregue o certificado do cliente.
- Configure o HttpClientHandler ou SocketsHttpHandler para incluir o certificado do cliente.
- Configure o retorno de chamada de validação de certificado do servidor se a validação personalizada for necessária.
Aqui está um exemplo usando 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);
Uso de propriedades de cabeçalho
Os cabeçalhos desempenham um papel crucial na comunicação HTTP, fornecendo metadados essenciais sobre a solicitação e a resposta. Ao trabalhar com HttpClient
no .NET, você pode definir e gerenciar várias propriedades de cabeçalho para controlar o comportamento de suas solicitações e respostas HTTP. Compreender como usar essas propriedades de cabeçalho de forma eficaz pode ajudá-lo a garantir que seu aplicativo se comunique de forma eficiente e segura com serviços Web.
Definir cabeçalhos de solicitação
Os cabeçalhos de solicitação são usados para fornecer informações adicionais ao servidor sobre a solicitação que está sendo feita. Os casos de uso comuns incluem a especificação do tipo de conteúdo, a configuração de tokens de autenticação e a adição de cabeçalhos personalizados. Você pode definir cabeçalhos de solicitação usando a DefaultRequestHeaders
propriedade de HttpClient
ou a propriedade Headers de HttpRequestMessage
.
Exemplo: definir cabeçalhos de solicitação personalizados
Definindo cabeçalhos de solicitação personalizados padrão no HttpClient
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Custom-Header", "value");
Definindo cabeçalhos de solicitação personalizados em HttpRequestMessage
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("Custom-Header", "value");
Exemplo: definir cabeçalhos de solicitação comuns
Ao trabalhar com HttpRequestMessage
no .NET, definir cabeçalhos de solicitação comuns é essencial para fornecer informações adicionais ao servidor sobre a solicitação que está sendo feita. Esses cabeçalhos podem incluir tokens de autenticação e muito mais. Configurar corretamente esses cabeçalhos garante que suas solicitações HTTP sejam processadas corretamente pelo servidor.
Para obter uma lista abrangente das propriedades comuns disponíveis no HttpRequestHeaders, consulte Propriedades.
Para definir cabeçalhos de solicitação comuns no HttpRequestMessage
, você pode usar a Headers
HttpRequestMessage
propriedade do objeto. Esta propriedade fornece acesso à HttpRequestHeaders
coleção, onde você pode adicionar ou modificar cabeçalhos conforme necessário.
Definindo cabeçalhos de solicitação padrão comuns em HttpClient
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Definindo cabeçalhos de solicitação comuns em HttpRequestMessage
using System.Net.Http.Headers;
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "token");
Exemplo: definir cabeçalhos de conteúdo
Os cabeçalhos de conteúdo são usados para fornecer informações adicionais sobre o corpo de uma solicitação ou resposta HTTP. Ao trabalhar com HttpClient
no .NET, você pode definir cabeçalhos de conteúdo para especificar o tipo de mídia, codificação e outros metadados relacionados ao conteúdo que está sendo enviado ou recebido. A configuração correta dos cabeçalhos de conteúdo garante que o servidor e o cliente possam interpretar e processar corretamente o conteúdo.
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);
Exemplo: Definir MaximumErrorResponseLength em HttpClient
O MaximumErrorResponseLength
uso permite que os desenvolvedores especifiquem o comprimento máximo do conteúdo da resposta de erro que o manipulador armazenará em buffer. Isso é útil para controlar a quantidade de dados que são lidos e armazenados na memória quando uma resposta de erro é recebida do servidor. Usando essa técnica, você pode evitar o uso excessivo de memória e melhorar o desempenho do seu aplicativo ao lidar com grandes respostas de erro.
Há algumas maneiras de fazer isso, vamos examinar TruncatedReadStream
a técnica neste exemplo:
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();
}
}
}
E exemplo de uso de 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);
}
Exemplo: Aplicar cabeçalhos CachePolicy
Aviso
HttpClient
não tem lógica interna para armazenar respostas em cache. Não há outra solução alternativa além de implementar todo o cache por conta própria. Simplesmente definir os cabeçalhos não alcançará o cache.
Ao migrar de HttpWebRequest
para o HttpClient
, é importante lidar corretamente com cabeçalhos relacionados ao cache, como pragma
e cache-control
. Esses cabeçalhos controlam como as respostas são armazenadas em cache e recuperadas, garantindo que seu aplicativo se comporte conforme o esperado em termos de desempenho e atualização de dados.
No HttpWebRequest
, você pode ter usado a CachePolicy
propriedade para definir esses cabeçalhos. No entanto, no HttpClient
, você precisa definir manualmente esses cabeçalhos na solicitação.
Código antigo usando HttpWebRequest
:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Na API mais antiga HttpWebRequest
, a aplicação CachePolicy
era simples devido ao seu suporte interno para esse recurso. No entanto, a API mais recente HttpClient
não fornece a mesma funcionalidade interna. Apesar disso, você pode obter um comportamento semelhante implementando um que adiciona manualmente cabeçalhos AddCacheControlHeaders
relacionados ao cache.
Novo código usando HttpClient
:
public static class CachePolicy
{
public static void AddCacheControlHeaders(HttpRequestMessage request, RequestCachePolicy policy)
Você pode encontrar a implementação de AddCacheControlHeaders
aqui.
AddCacheControlHeaders
Utilização:
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);
}
Uso de propriedades de buffer
Ao migrar de HttpWebRequest para HttpClient
o , é importante entender as diferenças em como essas duas APIs lidam com o buffer.
Código antigo usando HttpWebRequest
:
No HttpWebRequest
, você tem controle direto sobre as propriedades de buffer por meio das AllowWriteStreamBuffering
propriedades e AllowReadStreamBuffering
. Essas propriedades habilitam ou desabilitam o buffer de dados enviados e recebidos do servidor.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowReadStreamBuffering = true; // Default is `false`.
request.AllowWriteStreamBuffering = false; // Default is `true`.
Novo código usando HttpClient
:
Na HttpClient
, não há equivalentes diretos para as AllowWriteStreamBuffering
propriedades e AllowReadStreamBuffering
.
HttpClient não buffer corpos de solicitação por conta própria, em vez disso, delegando a responsabilidade para o HttpContent
usado. Conteúdos como StringContent
ou ByteArrayContent
logicamente já estão armazenados em buffer na memória, durante o uso StreamContent
não incorrerá em nenhum buffer por padrão. Para forçar o conteúdo a ser armazenado em buffer, você pode ligar HttpContent.LoadIntoBufferAsync
antes de enviar a solicitação. Eis um exemplo:
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);
No HttpClient
buffer de leitura está habilitado por padrão. Para evitá-lo, você pode especificar o HttpCompletionOption.ResponseHeadersRead
sinalizador ou usar o GetStreamAsync
auxiliar.
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);