Partilhar via


Diretrizes para usar HttpClient

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

Comportamento do DNS

HttpClient só resolve entradas DNS quando uma conexão é criada. Ele não rastreia nenhuma duração de tempo de vida (TTL) especificada 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 PooledConnectionLifetime propriedade, para que a 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 anterior HttpClient está configurado para reutilizar conexões por 15 minutos. Depois que o período de tempo especificado por PooledConnectionLifetime tiver 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 agrupadas

O grupo de conexões de um HttpClient está vinculado ao subjacente SocketsHttpHandler. Quando a HttpClient instância é 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á um impacto no desempenho devido à criação desnecessária de conexões. 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, consulte TCP TIME-WAIT no RFC 9293.) Se a taxa de solicitações for alta, o limite do sistema operacional de portas disponíveis pode estar esgotado. Para evitar problemas de exaustão de portas, recomendamos reutilizar HttpClient instâncias para o maior número possível de solicitações HTTP.

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

  • No .NET Core e no .NET 5+:

    • Use uma static instância ou singletonHttpClient com PooledConnectionLifetime definido para o intervalo desejado, como 2 minutos, dependendo das alterações de DNS esperadas. Isso resolve os problemas de exaustão da porta e alterações de DNS sem adicionar a sobrecarga do IHttpClientFactory. Se você precisar ser capaz de simular seu manipulador, você pode registrá-lo separadamente.

    Sugestão

    Se você usar apenas um número limitado de HttpClient instâncias, essa também é uma estratégia aceitável. O que importa é que eles não são criados e descartados a cada solicitação, pois cada um deles 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 cookies sem desabilitar completamente o tratamento de cookies.

    • Utilizando IHttpClientFactory, pode-se ter múltiplos clientes configurados de forma diferente para diferentes casos de uso. No entanto, esteja ciente de que os clientes criados na fábrica devem ser de curta duração e, uma vez que o cliente é criado, a fábrica não tem mais controle sobre ele.

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

      Se pretender a configurabilidade que IHttpClientFactory fornece, recomendamos usar a abordagem de cliente tipado.

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

    Advertência

    Se a sua aplicação requer cookies, é recomendável evitar o uso de IHttpClientFactory. O agrupamento das HttpMessageHandler instâncias resulta no compartilhamento de CookieContainer objetos. O compartilhamento inesperado CookieContainer pode causar vazamento de cookies entre partes não relacionadas da aplicação. Além disso, quando HandlerLifetime expira, o gestor é reciclado, o que significa que todos os cookies armazenados no seu CookieContainer são perdidos.

Para obter mais informações sobre como gerir 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 utilizando 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 erro HTTP transitório, configurado com pipeline de repetição que, a cada tentativa, recuará exponencialmente os intervalos de atraso.
  • Define uma vida útil de conexão agrupada de quinze minutos para o socketHandler.
  • Passa a lógica socketHandler para o resilienceHandler com a lógica de repetição.
  • Instancia um HttpClient compartilhado dado o resilienceHandler.

Consulte também