Compartilhar via


Classe System.Net.Http.HttpClient

Este artigo fornece comentários complementares à documentação de referência para esta API.

A HttpClient instância de classe atua como uma sessão para enviar solicitações HTTP. Uma HttpClient instância é uma coleção de configurações aplicadas a todas as solicitações executadas por essa instância. Além disso, cada HttpClient instância usa seu próprio pool de conexões, isolando suas solicitações de solicitações executadas por outras HttpClient instâncias.

Instância

HttpClient destina-se a ser instanciado uma vez e reutilizado ao longo da vida útil de um aplicativo. No .NET Core e no .NET 5+, o HttpClient agrupa conexões dentro da instância do manipulador e reutiliza uma conexão entre várias solicitações. Se você instanciar uma classe HttpClient para cada solicitação, o número de soquetes disponíveis sob cargas pesadas será esgotado. Esse desgaste resultará em erros SocketException.

Você pode configurar opções adicionais passando um "handler", como HttpClientHandler (ou SocketsHttpHandler no .NET Core 2.1 ou posterior), como parte do construtor. As propriedades de conexão no manipulador não podem ser alteradas depois que uma solicitação é enviada, portanto, um motivo para criar uma nova instância httpClient seria se você precisasse alterar as propriedades de conexão. Se solicitações diferentes exigirem configurações diferentes, isso também poderá levar um aplicativo a ter várias HttpClient instâncias, em que cada instância é configurada adequadamente e, em seguida, as solicitações são emitidas no cliente relevante.

O HttpClient só resolve entradas DNS quando uma conexão é criada. Ele não acompanha as durações TTL (tempo de vida útil) especificadas pelo servidor DNS. Se as entradas DNS forem alteradas regularmente, o que pode acontecer em alguns cenários de contêiner, o cliente não respeitará essas atualizações. Para resolver esse problema, você pode limitar o tempo de vida da conexão definindo a SocketsHttpHandler.PooledConnectionLifetime propriedade, de modo que a pesquisa de DNS seja necessária quando a conexão for substituída.

public class GoodController : ApiController
{
    private static readonly HttpClient httpClient;

    static GoodController()
    {
        var socketsHandler = new SocketsHttpHandler
        {
            PooledConnectionLifetime = TimeSpan.FromMinutes(2)
        };

        httpClient = new HttpClient(socketsHandler);
    }
}

Como alternativa à criação de apenas uma instância do HttpClient, você também pode usar IHttpClientFactory para gerenciar as instâncias do HttpClient para você. Para obter mais informações, confira Diretrizes para usar HttpClient.

Derivação

O HttpClient também atua como uma classe base para clientes HTTP mais específicos. Um exemplo seria um FacebookHttpClient que fornece métodos adicionais específicos para um serviço Web do Facebook (por exemplo, um GetFriends método). Classes derivadas não devem substituir os métodos virtuais na classe. Em vez disso, use uma sobrecarga de construtor que aceita HttpMessageHandler para configurar qualquer processamento de pré-solicitação ou pós-solicitação.

Transportes

HttpClient é uma API de alto nível que encapsula a funcionalidade de nível inferior disponível em cada plataforma em que é executada.

Em cada plataforma, HttpClient tenta usar o melhor transporte disponível:

Host/Runtime de back-end
Windows/.NET Framework HttpWebRequest
Windows/Mono HttpWebRequest
Windows/UWP WinHttpHandler nativo do Windows (compatível com HTTP 2.0)
Windows/.NET Core 1.0-2.0 WinHttpHandler nativo do Windows (compatível com HTTP 2.0)
macOS/Mono HttpWebRequest
macOS/.NET Core 1.0-2.0 Transporte HTTP baseado em libcurl (compatível com HTTP 2.0)
Linux/Mono HttpWebRequest
Linux/.NET Core 1.0-2.0 Transporte HTTP baseado em libcurl (compatível com HTTP 2.0)
.NET Core 2.1 e posterior System.Net.Http.SocketsHttpHandler

Os usuários também podem configurar um transporte específico para HttpClient invocando o construtor HttpClient que usa um HttpMessageHandler.

.NET Framework &Mono

Por padrão, no .NET Framework e no Mono, HttpWebRequest é usado para enviar solicitações ao servidor. Esse comportamento pode ser modificado especificando um manipulador diferente em uma das sobrecargas do construtor com um HttpMessageHandler parâmetro. Se você precisar de recursos como autenticação ou cache, poderá usar WebRequestHandler para definir as configurações e a instância poderá ser passada para o construtor. O manipulador retornado pode ser passado para uma sobrecarga de construtor que tem um parâmetro HttpMessageHandler.

.NET Core

A partir do .NET Core 2.1, a classe System.Net.Http.SocketsHttpHandler fornece a implementação usada por classes de rede HTTP de nível superior, no lugar da HttpClientHandler como a HttpClient. O uso de SocketsHttpHandler oferece várias vantagens:

  • Uma melhoria de desempenho significativa quando comparada com a implementação anterior.
  • A eliminação de dependências de plataforma, que simplifica a implantação e a manutenção. Por exemplo, libcurl não é mais uma dependência do .NET Core para macOS e .NET Core para Linux.
  • Comportamento consistente em todas as plataformas .NET.

Se essa alteração for indesejável, no Windows, você poderá continuar a usar WinHttpHandler referenciando seu pacote NuGet e passando-o manualmente para o construtor do HttpClient .

Configurar o comportamento usando opções de configuração de runtime

Determinados aspectos do HttpClientcomportamento são personalizáveis por meio de opções de configuração do Runtime. No entanto, o comportamento desses switches varia entre as versões do .NET. Por exemplo, no .NET Core 2.1 – 3.1, você pode configurar se SocketsHttpHandler é usado por padrão, mas essa opção não está mais disponível a partir do .NET 5.

Agrupamento de conexões

O HttpClient agrupa conexões HTTP sempre que possível e as usa para mais de uma solicitação. Isso pode ter um benefício de desempenho significativo, especialmente para solicitações HTTPS, já que o handshake de conexão só é feito uma vez.

As propriedades do pool de conexão podem ser configuradas em um HttpClientHandler ou SocketsHttpHandler passado durante a construção, incluindo MaxConnectionsPerServer, PooledConnectionIdleTimeout e PooledConnectionLifetime.

A eliminação da instância do HttpClient fecha as conexões abertas e cancela as solicitações pendentes.

Observação

Se você enviar simultaneamente solicitações HTTP/1.1 para o mesmo servidor, novas conexões poderão ser criadas. Mesmo se você reutilizar a HttpClient instância, se a taxa de solicitações for alta ou se houver limitações de firewall, isso poderá esgotar os soquetes disponíveis devido aos temporizadores de limpeza TCP padrão. Para limitar o número de conexões simultâneas, você pode definir a MaxConnectionsPerServer propriedade. Por padrão, o número de conexões HTTP/1.1 simultâneas é ilimitado.

Bufferização e tempo de vida da solicitação

Por padrão, os métodos HttpClient (exceto GetStreamAsync) armazenam em buffer as respostas do servidor, lendo todo o corpo da resposta na memória antes de retornar o resultado assíncrono. Essas solicitações continuarão até que ocorra um destes procedimentos:

Você pode alterar o comportamento de buffer por solicitação usando o HttpCompletionOption parâmetro disponível em algumas sobrecargas de método. Esse argumento pode ser usado para especificar se o Task<TResult> deve ser considerado concluído depois de ler apenas os cabeçalhos de resposta ou depois de ler e armazenar o conteúdo da resposta em buffer.

Se o aplicativo que usa HttpClient e classes relacionadas no namespace System.Net.Http pretende baixar grandes quantidades de dados (50 megabytes ou mais), o aplicativo deve fazer streaming desses downloads e não usar o buffer padrão. Se você usar o buffer padrão, o uso da memória do cliente ficará muito grande, potencialmente resultando em um desempenho substancialmente reduzido.

Acesso thread-safe

Os métodos a seguir são thread safe:

Proxys

Por padrão, o HttpClient lê a configuração de proxy de variáveis de ambiente ou configurações de usuário/sistema, dependendo da plataforma. Você pode alterar esse comportamento passando um WebProxy ou IWebProxy para, em ordem de precedência:

  • A propriedade Proxy em um HttpClientHandler passado como parâmetro durante a construção do HttpClient
  • A propriedade estática DefaultProxy (afeta todas as instâncias)

Você pode desabilitar o proxy usando UseProxy. A configuração padrão para usuários do Windows é tentar detectar um proxy usando a descoberta de rede, o que pode ser lento. Para aplicativos de alta taxa de transferência em que se sabe que um proxy não é necessário, você deve desabilitar o proxy.

As configurações de proxy (como Credentials) devem ser alteradas somente antes que a primeira solicitação seja feita usando o HttpClient. As alterações feitas após o uso do HttpClient pela primeira vez podem não ser refletidas em solicitações subsequentes.

Tempos limite

Você pode usar Timeout para definir um tempo limite padrão para todas as solicitações HTTP da instância do HttpClient. O tempo limite só se aplica aos métodos xxxAsync que fazem com que uma solicitação/resposta seja iniciada. Se o tempo limite for atingido, a Task<TResult> solicitação será cancelada.

Você pode definir alguns tempos limite adicionais se passar uma instância SocketsHttpHandler na construção do objeto HttpClient.

Propriedade Descrição
ConnectTimeout Especifica um tempo limite usado quando uma solicitação requer a criação de uma nova conexão TCP. Se o tempo limite ocorrer, a solicitação Task<TResult> será cancelada.
PooledConnectionLifetime Especifica um tempo limite a ser usado para cada conexão no pool de conexões. Se a conexão estiver ociosa, a conexão será fechada imediatamente; caso contrário, a conexão será fechada no final da solicitação atual.
PooledConnectionIdleTimeout Se uma conexão no pool de conexões estiver ociosa por esse tempo, a conexão será fechada.
Expect100ContinueTimeout Se a solicitação tiver um cabeçalho "Expect: 100-continue", ela atrasará o envio de conteúdo até o tempo limite ou até que uma resposta "100-continue" seja recebida.

O HttpClient só resolve as entradas DNS quando as conexões são criadas. Ele não acompanha as durações TTL (tempo de vida útil) especificadas pelo servidor DNS. Se as entradas DNS estiverem mudando regularmente, o que pode acontecer em alguns cenários de contêiner, você poderá usar o PooledConnectionLifetime para limitar o tempo de vida da conexão para que a pesquisa de DNS seja necessária ao substituir a conexão.