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, você pode limitar o tempo de vida da conexão definindo a propriedade, para que a PooledConnectionLifetime pesquisa de DNS seja repetida quando a conexão for substituída. Considere o seguinte 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), essa 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. As a result, there's a performance penalty for unnecessary connection creation. 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.

To summarize recommended HttpClient use in terms of lifetime management, you should use either long-lived clients and set PooledConnectionLifetime (.NET Core and .NET 5+) or short-lived clients created by IHttpClientFactory.

  • In .NET Core and .NET 5+:

    • Use a static or singletonHttpClient instance with PooledConnectionLifetime set to the desired interval, such as 2 minutes, depending on expected DNS changes. Isso resolve os problemas de exaustão da porta e alterações de DNS sem adicionar a sobrecarga do IHttpClientFactory. If you need to be able to mock your handler, you can register it separately.

    Tip

    Se você usar apenas um número limitado de HttpClient instâncias, essa também é uma estratégia aceitável. What matters is that they're not created and disposed with each request, as they each contain a connection pool. 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.

      The factory pools HttpMessageHandler instances, and, if its lifetime hasn't expired, a handler can be reused from the pool when the factory creates a new HttpClient instance. Essa reutilização evita problemas de exaustão do soquete.

      If you desire the configurability that IHttpClientFactory provides, we recommend using the typed-client approach.

  • In .NET Framework, use IHttpClientFactory to manage your HttpClient instances. 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

    If your app requires cookies, it's recommended to avoid using IHttpClientFactory. Pooling the HttpMessageHandler instances results in sharing of CookieContainer objects. Unanticipated CookieContainer sharing might leak cookies between unrelated parts of the application. Moreover, when HandlerLifetime expires, the handler is recycled, meaning that all cookies stored in its CookieContainer are lost.

For more information about managing HttpClient lifetime with IHttpClientFactory, see IHttpClientFactory guidelines.

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.
  • Specifies a transient HTTP error handler, configured with retry pipeline that with each attempt will exponentially backoff delay intervals.
  • Define uma vida útil de conexão agrupada de quinze minutos para o socketHandler.
  • Passes the socketHandler to the resilienceHandler with the retry logic.
  • Instantiates a shared HttpClient given the resilienceHandler.

Consulte também