Compartilhar via


Diretrizes para usar o HttpClient

A classe System.Net.Http.HttpClient envia solicitações HTTP e recebe respostas HTTP de um recurso identificado por um URI. Uma instância HttpClient é uma coleção de configurações aplicadas a todas as solicitações executadas por essa instância e cada instância usa seu próprio pool de conexões, o que isola suas solicitações de outras. A partir do .NET Core 2.1, a classe SocketsHttpHandler fornece a implementação, tornando o comportamento consistente em todas as plataformas.

Comportamento DNS

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, o cliente não respeitará essas atualizações. Para resolver esse problema, limite o tempo de vida da conexão definindo a propriedade, de modo que a PooledConnectionLifetime pesquisa de DNS seja repetida quando a conexão for substituída. Considere este exemplo:

var handler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(15) // Recreate every 15 minutes
};
var sharedClient = new HttpClient(handler);

O HttpClient anterior é configurado para reutilizar conexões por 15 minutos. Depois que o período especificado pelo PooledConnectionLifetime decorrido e a conexão tiver concluído sua última solicitação associada (se houver), a conexão será fechada. Se houver alguma solicitação aguardando na fila, uma nova conexão será criada conforme necessário.

O intervalo de 15 minutos foi escolhido arbitrariamente para fins ilustrativos. Você deve escolher o valor com base na frequência esperada de DNS ou outras alterações de rede.

Conexões em pool

O pool de conexões de um HttpClient está vinculado ao SocketsHttpHandler subjacente. Quando a instância HttpClient é descartada, ela descarta todas as conexões existentes dentro do pool. Se, posteriormente, você enviar uma solicitação para o mesmo servidor, uma nova conexão deverá ser recriada. Como resultado, há uma penalidade de desempenho para a criação de conexão desnecessária. Além disso, as portas TCP não são liberadas imediatamente após o fechamento da conexão. (Para obter mais informações sobre isso, confira o TIME-WAIT do TCP no RFC 9293.) Se a taxa de solicitações for alta, o limite de portas disponíveis do sistema operacional poderá estar esgotado. Para evitar problemas de esgotamento de portas, recomendamos reutilizar as instâncias de HttpClient para o maior número possível de solicitações HTTP.

Para resumir o uso recomendado de HttpClient em termos de gerenciamento de tempo de vida, você deve usar clientes de longa duração e configurar o PooledConnectionLifetime (.NET Core e .NET 5+) ou clientes de curta duração criados por IHttpClientFactory.

  • No .NET Core e .NET 5+:

    • Use uma instância de static ou singletonHttpClient com PooledConnectionLifetime definida para o intervalo desejado, como 2 minutos, de acordo com as alterações de DNS esperadas. Isso resolve os problemas de esgotamento de portas e alterações de DNS sem adicionar a sobrecarga de IHttpClientFactory. Se você precisar simular seu manipulador, poderá registrá-lo separadamente.

    Dica

    Se você usar apenas um número limitado de HttpClient instâncias, essa estratégia também será aceitável. O que importa é que não sejam criadas e descartadas a cada solicitação, já que cada uma delas contém um pool de conexões. O uso de mais de uma instância é necessário para cenários com vários proxies ou para separar contêineres de cookie sem desabilitar completamente a manipulação de cookies.

    • Usando IHttpClientFactory, você pode ter vários clientes configurados de forma diferente para diferentes casos de uso. No entanto, lembre-se de que os clientes criados pela fábrica devem ter vida útil curta e, depois que o cliente for criado, a fábrica não terá mais controle sobre ele.

      A fábrica agrupa instâncias de HttpMessageHandler e, se seu tempo de vida não tiver expirado, um manipulador poderá ser reutilizado do pool quando a fábrica criar uma nova instância de HttpClient. Essa reutilização evita problemas de esgotamento do soquete.

      Se você desejar a capacidade de configuração que o IHttpClientFactory, recomendamos usar a abordagem de cliente com tipo.

  • No .NET Framework, use IHttpClientFactory para gerenciar suas instâncias HttpClient. Se não usar o alocador e, em vez disso, criar por conta própria uma nova instância de cliente para cada solicitação, você poderá esgotar as portas disponíveis.

    Aviso

    Se o seu aplicativo exigir cookies, é recomendável evitar o uso de IHttpClientFactory. Agrupar as instâncias HttpMessageHandler resulta no compartilhamento de objetos CookieContainer. O compartilhamento imprevisto CookieContainer pode vazar cookies entre partes não relacionadas do aplicativo. Além disso, quando HandlerLifetime expira, o handler é reciclado, o que significa que todos os cookies armazenados em seu CookieContainer são apagados.

Para obter mais informações sobre como gerenciar o tempo de vida de HttpClient com IHttpClientFactory, consulte as diretrizes de IHttpClientFactory.

Resiliência com clientes estáticos

É possível configurar um cliente static ou singleton para usar qualquer número de pipelines de resiliência usando o seguinte padrão:

using Microsoft.Extensions.Http.Resilience;
using Polly;

class MyClass
{
    static HttpClient? s_httpClient;

    MyClass()
    {
        var retryPipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
            .AddRetry(new HttpRetryStrategyOptions
            {
                BackoffType = DelayBackoffType.Exponential,
                MaxRetryAttempts = 3
            })
            .Build();

        var socketHandler = new SocketsHttpHandler
        {
            PooledConnectionLifetime = TimeSpan.FromMinutes(15)
        };
        var resilienceHandler = new ResilienceHandler(retryPipeline)
        {
            InnerHandler = socketHandler,
        };

        s_httpClient = new HttpClient(resilienceHandler);
    }
}

O código anterior:

  • Depende do pacote NuGet Microsoft.Extensions.Http.Resilience.
  • Especifica um manipulador de erros HTTP transitório, configurado com o pipeline de repetição que, com cada tentativa, fará intervalos de atraso de retirada exponencialmente.
  • Define um tempo de vida de conexão em pool de quinze minutos para o socketHandler.
  • Passa o socketHandler para o resilienceHandler com a lógica de repetição.
  • Cria uma instância de HttpClient compartilhada dado o resilienceHandler.

Confira também