Linee guida per l'uso di HttpClient

La classe System.Net.Http.HttpClient invia richieste HTTP e riceve risposte HTTP da una risorsa identificata da un URI. Un'istanza HttpClient è una raccolta di impostazioni applicate a tutte le richieste eseguite da tale istanza; ogni istanza usa il proprio pool di connessioni, che isola le richieste da altri utenti. A partire da .NET Core 2.1, la SocketsHttpHandler classe fornisce l'implementazione, rendendo coerente il comportamento in tutte le piattaforme.

Comportamento DNS

HttpClient risolve solo le voci DNS quando viene creata una connessione. Non tiene traccia delle durate (TTL) specificate dal server DNS. Se le voci DNS cambiano regolarmente, che possono verificarsi in alcuni scenari, il client non rispetterà tali aggiornamenti. Per risolvere questo problema, è possibile limitare la durata della connessione impostando la proprietà PooledConnectionLifetime, in modo che la ricerca DNS venga ripetuta quando la connessione viene sostituita. Si consideri l'esempio seguente:

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

Il precedente HttpClient è configurato per riutilizzare le connessioni per 15 minuti. Dopo che è trascorso l'intervallo di tempo specificato da PooledConnectionLifetime , la connessione viene chiusa e ne viene creata una nuova.

Connessioni in pool

Il pool di connessioni per un HttpClient oggetto è collegato all'oggetto sottostante SocketsHttpHandler. Quando l'istanza HttpClient viene eliminata, elimina tutte le connessioni esistenti all'interno del pool. Se in seguito si invia una richiesta allo stesso server, è necessario ricreare una nuova connessione. Di conseguenza, si verifica una riduzione delle prestazioni per la creazione di connessioni non necessarie. Inoltre, le porte TCP non vengono rilasciate immediatamente dopo la chiusura della connessione. Per altre informazioni, vedere TCP TIME-WAIT in RFC 9293. Se la frequenza delle richieste è elevata, il limite del sistema operativo delle porte disponibili potrebbe essere esaurito. Per evitare problemi di esaurimento delle porte, è consigliabile riutilizzare HttpClient le istanze per il maggior numero possibile di richieste HTTP.

Per riepilogare l'uso consigliato HttpClient in termini di gestione della durata, è consigliabile usare client di lunga durata e impostare PooledConnectionLifetime (.NET Core e .NET 5+) o client di breve durata creati da IHttpClientFactory.

  • In .NET Core e .NET 5+:

    • Usare un'istanza static singletonHttpClient o con PooledConnectionLifetime impostato sull'intervallo desiderato, ad esempio 2 minuti, a seconda delle modifiche DNS previste. In questo modo vengono risolti sia i problemi di esaurimento delle porte che di modifiche DNS senza aggiungere il sovraccarico di IHttpClientFactory. Se è necessario essere in grado di simulare il gestore, è possibile registrarlo separatamente.

    Suggerimento

    Se si usa solo un numero limitato di HttpClient istanze, questa è anche una strategia accettabile. Ciò che conta è che non vengono creati ed eliminati con ogni richiesta, perché ognuno contiene un pool di connessioni. L'uso di più istanze è necessario per scenari con più proxy o per separare i contenitori di cookie senza disabilitare completamente la gestione dei cookie.

    • Usando IHttpClientFactory, è possibile avere più client configurati in modo diverso per casi d'uso diversi. Tenere tuttavia presente che i client creati dalla factory devono essere di breve durata e dopo la creazione del client, la factory non ha più il controllo su di esso.

      Le istanze del pool HttpMessageHandler di factory e, se la durata non è scaduta, un gestore può essere riutilizzato dal pool quando la factory crea una nuova HttpClient istanza. Questo riutilizzo evita eventuali problemi di esaurimento del socket.

      Se si desidera la configurabilità fornitaIHttpClientFactory, è consigliabile usare l'approccio tipizzato-client.

  • In .NET Framework usare IHttpClientFactory per gestire le HttpClient istanze. Se non si usa la factory e si crea invece una nuova istanza client per ogni richiesta manualmente, è possibile esaurire le porte disponibili.

    Suggerimento

    Se l'app richiede cookie, è consigliabile disabilitare la gestione automatica dei cookie o evitare IHttpClientFactory. Il pooling delle istanze comporta la HttpMessageHandler condivisione di CookieContainer oggetti. La condivisione di oggetti imprevisti CookieContainer comporta spesso codice non corretto.

Per altre informazioni sulla gestione della durata con IHttpClientFactory, vedereIHttpClientFactorylinee guida.HttpClient

Resilienza con client statici

È possibile configurare un static client singleton o per usare un numero qualsiasi di pipeline di resilienza usando il modello seguente:

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

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,
};

var httpClient = new HttpClient(resilienceHandler);

Il codice precedente:

  • Si basa sul pacchetto NuGet Microsoft.Extensions.Http.Resilience .
  • Specifica un gestore degli errori HTTP temporanei, configurato con la pipeline di ripetizione dei tentativi che con ogni tentativo ritarderà in modo esponenziale gli intervalli di ritardo del backoff.
  • Definisce una durata di connessione in pool di quindici minuti per .socketHandler
  • socketHandler Passa a con resilienceHandler la logica di ripetizione dei tentativi.
  • Crea un'istanza di un HttpClient dato oggetto resilienceHandler.

Importante

La Microsoft.Extensions.Http.Resilience libreria è attualmente contrassegnata come sperimentale e potrebbe cambiare in futuro.

Vedi anche