Effettuare richieste HTTP con la classe HttpClient

In questo articolo si apprenderà come effettuare richieste HTTP e gestire le risposte con la HttpClient classe .

Importante

Tutte le richieste HTTP di esempio hanno come destinazione uno degli URL seguenti:

Gli endpoint HTTP restituiscono in genere dati JSON (JavaScript Object Notation), ma non sempre. Per praticità, il pacchetto NuGet System.Net.Http.Json facoltativo fornisce diversi metodi di estensione per HttpClient e HttpContent che eseguono la serializzazione automatica e la deserializzazione usando System.Text.Json. Gli esempi che seguono richiamano l'attenzione sui luoghi in cui sono disponibili queste estensioni.

Suggerimento

Tutto il codice sorgente di questo articolo è disponibile nel repository GitHub: .NET Docs .

Creare una chiave HttpClient

La maggior parte degli esempi seguenti riutilizza la stessa HttpClient istanza e pertanto deve essere configurata una sola volta. Per creare un oggetto HttpClient, usare il costruttore della HttpClient classe . Per altre informazioni, vedere Linee guida per l'uso di HttpClient.

// HttpClient lifecycle management best practices:
// https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
private static HttpClient sharedClient = new()
{
    BaseAddress = new Uri("https://jsonplaceholder.typicode.com"),
};

Il codice precedente:

  • Crea un'istanza di una nuova HttpClient istanza come static variabile. In base alle linee guida, è consigliabile riutilizzare HttpClient le istanze durante il ciclo di vita dell'applicazione.
  • Imposta su HttpClient.BaseAddress"https://jsonplaceholder.typicode.com".

Questa HttpClient istanza usa l'indirizzo di base durante l'esecuzione di richieste successive. Per applicare altre configurazioni, prendere in considerazione:

Suggerimento

In alternativa, è possibile creare HttpClient istanze usando un approccio basato su modello factory che consente di configurare un numero qualsiasi di client e utilizzarli come servizi di inserimento delle dipendenze. Per altre informazioni, vedere Http client factory con .NET.

Effettuare una richiesta HTTP

Per effettuare una richiesta HTTP, chiamare una delle API seguenti:

Metodo HTTP API
GET HttpClient.GetAsync
GET HttpClient.GetByteArrayAsync
GET HttpClient.GetStreamAsync
GET HttpClient.GetStringAsync
POST HttpClient.PostAsync
PUT HttpClient.PutAsync
PATCH HttpClient.PatchAsync
DELETE HttpClient.DeleteAsync
USER SPECIFIED HttpClient.SendAsync

† Richiesta A USER SPECIFIED indica che il SendAsync metodo accetta qualsiasi oggetto validoHttpMethod.

Avviso

L'esecuzione di richieste HTTP è considerata un lavoro associato a I/O di rete. Anche se esiste un metodo sincrono HttpClient.Send , è consigliabile usare invece le API asincrone, a meno che non si abbia un buon motivo per non farlo.

Contenuto HTTP

Il HttpContent tipo viene usato per rappresentare un corpo dell'entità HTTP e le intestazioni di contenuto corrispondenti. Per i metodi HTTP (o metodi di richiesta) che richiedono un corpo, POST, PUTe PATCH, si usa la HttpContent classe per specificare il corpo della richiesta. La maggior parte degli esempi illustra come preparare la StringContent sottoclasse con un payload JSON, ma esistono altre sottoclassi per tipi di contenuto (MIME) diversi.

La HttpContent classe viene usata anche per rappresentare il corpo della risposta dell'oggetto HttpResponseMessage, accessibile nella HttpResponseMessage.Content proprietà .

HTTP Get

Una GET richiesta non deve inviare un corpo e viene usata (come indica il nome del metodo) per recuperare (o ottenere) dati da una risorsa. Per effettuare una richiesta HTTP GET , dato un HttpClient e un URI, usare il HttpClient.GetAsync metodo :

static async Task GetAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.GetAsync("todos/3");
    
    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();
    
    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output:
    //   GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1
    //   {
    //     "userId": 1,
    //     "id": 3,
    //     "title": "fugiat veniam minus",
    //     "completed": false
    //   }
}

Il codice precedente:

  • Effettua una GET richiesta a "https://jsonplaceholder.typicode.com/todos/3".
  • Assicura che la risposta venga eseguita correttamente.
  • Scrive i dettagli della richiesta nella console.
  • Legge il corpo della risposta come stringa.
  • Scrive il corpo della risposta JSON nella console.

WriteRequestToConsole è un metodo di estensione personalizzato che non fa parte del framework, ma se si è curiosi di come viene implementato, prendere in considerazione il codice C# seguente:

static class HttpResponseMessageExtensions
{
    internal static void WriteRequestToConsole(this HttpResponseMessage response)
    {
        if (response is null)
        {
            return;
        }

        var request = response.RequestMessage;
        Console.Write($"{request?.Method} ");
        Console.Write($"{request?.RequestUri} ");
        Console.WriteLine($"HTTP/{request?.Version}");        
    }
}

Questa funzionalità viene usata per scrivere i dettagli della richiesta nella console nel formato seguente:

<HTTP Request Method> <Request URI> <HTTP/Version>

Ad esempio, la GET richiesta di https://jsonplaceholder.typicode.com/todos/3 restituire il messaggio seguente:

GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1

HTTP Get from JSON

L'endpoint https://jsonplaceholder.typicode.com/todos restituisce una matrice JSON di oggetti "todo". La struttura JSON è simile alla seguente:

[
  {
    "userId": 1,
    "id": 1,
    "title": "example title",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "another example title",
    "completed": true
  },
]

L'oggetto C# Todo è definito come segue:

public record class Todo(
    int? UserId = null,
    int? Id = null,
    string? Title = null,
    bool? Completed = null);

Si tratta di un record class tipo, con proprietà facoltative Id, TitleCompleted, e UserId . Per altre informazioni sul record tipo, vedere Introduzione ai tipi di record in C#. Per deserializzare GET automaticamente le richieste in un oggetto C# fortemente tipizzato, usare il GetFromJsonAsync metodo di estensione che fa parte del pacchetto NuGet System.Net.Http.Json .

static async Task GetFromJsonAsync(HttpClient httpClient)
{
    var todos = await httpClient.GetFromJsonAsync<List<Todo>>(
        "todos?userId=1&completed=false");

    Console.WriteLine("GET https://jsonplaceholder.typicode.com/todos?userId=1&completed=false HTTP/1.1");
    todos?.ForEach(Console.WriteLine);
    Console.WriteLine();

    // Expected output:
    //   GET https://jsonplaceholder.typicode.com/todos?userId=1&completed=false HTTP/1.1
    //   Todo { UserId = 1, Id = 1, Title = delectus aut autem, Completed = False }
    //   Todo { UserId = 1, Id = 2, Title = quis ut nam facilis et officia qui, Completed = False }
    //   Todo { UserId = 1, Id = 3, Title = fugiat veniam minus, Completed = False }
    //   Todo { UserId = 1, Id = 5, Title = laboriosam mollitia et enim quasi adipisci quia provident illum, Completed = False }
    //   Todo { UserId = 1, Id = 6, Title = qui ullam ratione quibusdam voluptatem quia omnis, Completed = False }
    //   Todo { UserId = 1, Id = 7, Title = illo expedita consequatur quia in, Completed = False }
    //   Todo { UserId = 1, Id = 9, Title = molestiae perspiciatis ipsa, Completed = False }
    //   Todo { UserId = 1, Id = 13, Title = et doloremque nulla, Completed = False }
    //   Todo { UserId = 1, Id = 18, Title = dolorum est consequatur ea mollitia in culpa, Completed = False }
}

Nel codice precedente:

  • Viene effettuata una GET richiesta a "https://jsonplaceholder.typicode.com/todos?userId=1&completed=false".
    • La stringa di query rappresenta i criteri di filtro per la richiesta.
  • La risposta viene deserializzata automaticamente in un oggetto List<Todo> quando ha esito positivo.
  • I dettagli della richiesta vengono scritti nella console, insieme a ogni Todo oggetto .

HTTP Post

Una POST richiesta invia dati al server per l'elaborazione. L'intestazione Content-Type della richiesta indica il tipo MIME inviato dal corpo. Per effettuare una richiesta HTTP POST , in base HttpClient a e Uria , usare il HttpClient.PostAsync metodo :

static async Task PostAsync(HttpClient httpClient)
{
    using StringContent jsonContent = new(
        JsonSerializer.Serialize(new
        {
            userId = 77,
            id = 1,
            title = "write code sample",
            completed = false
        }),
        Encoding.UTF8,
        "application/json");

    using HttpResponseMessage response = await httpClient.PostAsync(
        "todos",
        jsonContent);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();
    
    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output:
    //   POST https://jsonplaceholder.typicode.com/todos HTTP/1.1
    //   {
    //     "userId": 77,
    //     "id": 201,
    //     "title": "write code sample",
    //     "completed": false
    //   }
}

Il codice precedente:

  • Prepara un'istanza StringContent con il corpo JSON della richiesta (tipo MIME di "application/json").
  • Effettua una POST richiesta a "https://jsonplaceholder.typicode.com/todos".
  • Assicura che la risposta venga completata correttamente e scriva i dettagli della richiesta nella console.
  • Scrive il corpo della risposta come stringa nella console.

HTTP Post come JSON

Per serializzare POST automaticamente gli argomenti della richiesta e deserializzare le risposte in oggetti C# fortemente tipizzati, usare il PostAsJsonAsync metodo di estensione che fa parte del pacchetto NuGet System.Net.Http.Json .

static async Task PostAsJsonAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.PostAsJsonAsync(
        "todos", 
        new Todo(UserId: 9, Id: 99, Title: "Show extensions", Completed: false));

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var todo = await response.Content.ReadFromJsonAsync<Todo>();
    Console.WriteLine($"{todo}\n");

    // Expected output:
    //   POST https://jsonplaceholder.typicode.com/todos HTTP/1.1
    //   Todo { UserId = 9, Id = 201, Title = Show extensions, Completed = False }
}

Il codice precedente:

  • Serializza l'istanza Todo come JSON e invia una POST richiesta a "https://jsonplaceholder.typicode.com/todos".
  • Assicura che la risposta venga completata correttamente e scriva i dettagli della richiesta nella console.
  • Deserializza il corpo della risposta in un'istanza Todo e scrive nella Todo console.

HTTP Put

Il PUT metodo di richiesta sostituisce una risorsa esistente o ne crea una nuova usando il payload del corpo della richiesta. Per effettuare una richiesta HTTP PUT , dato un HttpClient e un URI, usare il HttpClient.PutAsync metodo :

static async Task PutAsync(HttpClient httpClient)
{
    using StringContent jsonContent = new(
        JsonSerializer.Serialize(new 
        {
            userId = 1,
            id = 1,
            title = "foo bar",
            completed = false
        }),
        Encoding.UTF8,
        "application/json");

    using HttpResponseMessage response = await httpClient.PutAsync(
        "todos/1",
        jsonContent);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();
    
    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output:
    //   PUT https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
    //   {
    //     "userId": 1,
    //     "id": 1,
    //     "title": "foo bar",
    //     "completed": false
    //   }
}

Il codice precedente:

  • Prepara un'istanza StringContent con il corpo JSON della richiesta (tipo MIME di "application/json").
  • Effettua una PUT richiesta a "https://jsonplaceholder.typicode.com/todos/1".
  • Assicura che la risposta sia riuscita e scriva i dettagli della richiesta e il corpo della risposta JSON nella console.

HTTP Put as JSON

Per serializzare PUT automaticamente gli argomenti della richiesta e deserializzare le risposte in oggetti C# fortemente tipizzati, usare il PutAsJsonAsync metodo di estensione che fa parte del pacchetto NuGet System.Net.Http.Json .

static async Task PutAsJsonAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.PutAsJsonAsync(
        "todos/5",
        new Todo(Title: "partially update todo", Completed: true));

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var todo = await response.Content.ReadFromJsonAsync<Todo>();
    Console.WriteLine($"{todo}\n");

    // Expected output:
    //   PUT https://jsonplaceholder.typicode.com/todos/5 HTTP/1.1
    //   Todo { UserId = , Id = 5, Title = partially update todo, Completed = True }
}

Il codice precedente:

  • Serializza l'istanza Todo come JSON e invia una PUT richiesta a "https://jsonplaceholder.typicode.com/todos/5".
  • Assicura che la risposta venga completata correttamente e scriva i dettagli della richiesta nella console.
  • Deserializza il corpo della risposta in un'istanza Todo e scrive nella Todo console.

HTTP Patch

La PATCH richiesta è un aggiornamento parziale di una risorsa esistente. Non crea una nuova risorsa e non è progettata per sostituire una risorsa esistente. Aggiorna invece solo parzialmente una risorsa. Per effettuare una richiesta HTTP PATCH , dato un HttpClient e un URI, usare il HttpClient.PatchAsync metodo :

static async Task PatchAsync(HttpClient httpClient)
{
    using StringContent jsonContent = new(
        JsonSerializer.Serialize(new
        {
            completed = true
        }),
        Encoding.UTF8,
        "application/json");

    using HttpResponseMessage response = await httpClient.PatchAsync(
        "todos/1",
        jsonContent);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output
    //   PATCH https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
    //   {
    //     "userId": 1,
    //     "id": 1,
    //     "title": "delectus aut autem",
    //     "completed": true
    //   }
}

Il codice precedente:

  • Prepara un'istanza StringContent con il corpo JSON della richiesta (tipo MIME di "application/json").
  • Effettua una PATCH richiesta a "https://jsonplaceholder.typicode.com/todos/1".
  • Assicura che la risposta sia riuscita e scriva i dettagli della richiesta e il corpo della risposta JSON nella console.

Non esistono metodi di estensione per PATCH le richieste nel System.Net.Http.Json pacchetto NuGet.

Eliminazione HTTP

Una DELETE richiesta elimina una risorsa esistente. Una DELETE richiesta è idempotente ma non sicura, ovvero più DELETE richieste alle stesse risorse producono lo stesso risultato, ma la richiesta influisce sullo stato della risorsa. Per effettuare una richiesta HTTP DELETE , dato un HttpClient e un URI, usare il HttpClient.DeleteAsync metodo :

static async Task DeleteAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.DeleteAsync("todos/1");
    
    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output
    //   DELETE https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
    //   {}
}

Il codice precedente:

  • Effettua una DELETE richiesta a "https://jsonplaceholder.typicode.com/todos/1".
  • Assicura che la risposta venga completata correttamente e scriva i dettagli della richiesta nella console.

Suggerimento

La risposta a una richiesta (proprio come una DELETEPUT richiesta) può includere o meno un corpo.

Intestazione HTTP

La HEAD richiesta è simile a una GET richiesta. Anziché restituire la risorsa, restituisce solo le intestazioni associate alla risorsa. Una risposta alla HEAD richiesta non restituisce un corpo. Per effettuare una richiesta HTTP HEAD , dato un HttpClient e un URI, usare il HttpClient.SendAsync metodo con il HttpMethod set su HttpMethod.Head:

static async Task HeadAsync(HttpClient httpClient)
{
    using HttpRequestMessage request = new(
        HttpMethod.Head, 
        "https://www.example.com");

    using HttpResponseMessage response = await httpClient.SendAsync(request);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    foreach (var header in response.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    Console.WriteLine();

    // Expected output:
    //   HEAD https://www.example.com/ HTTP/1.1
    //   Accept-Ranges: bytes
    //   Age: 550374
    //   Cache-Control: max-age=604800
    //   Date: Wed, 10 Aug 2022 17:24:55 GMT
    //   ETag: "3147526947"
    //   Server: ECS, (cha / 80E2)
    //   X-Cache: HIT
}

Il codice precedente:

  • Effettua una HEAD richiesta a "https://www.example.com/".
  • Assicura che la risposta venga completata correttamente e scriva i dettagli della richiesta nella console.
  • Scorre tutte le intestazioni di risposta, scrivendo ognuna nella console.

Opzioni HTTP

La OPTIONS richiesta viene usata per identificare i metodi HTTP supportati da un server o un endpoint. Per effettuare una richiesta HTTP OPTIONS , dato un HttpClient e un URI, usare il HttpClient.SendAsync metodo con il HttpMethod set su HttpMethod.Options:

static async Task OptionsAsync(HttpClient httpClient)
{
    using HttpRequestMessage request = new(
        HttpMethod.Options, 
        "https://www.example.com");

    using HttpResponseMessage response = await httpClient.SendAsync(request);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    foreach (var header in response.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    Console.WriteLine();

    // Expected output
    //   OPTIONS https://www.example.com/ HTTP/1.1
    //   Allow: OPTIONS, GET, HEAD, POST
    //   Content-Type: text/html; charset=utf-8
    //   Expires: Wed, 17 Aug 2022 17:28:42 GMT
    //   Content-Length: 0
}

Il codice precedente:

  • Invia una OPTIONS richiesta HTTP a "https://www.example.com/".
  • Assicura che la risposta venga completata correttamente e scriva i dettagli della richiesta nella console.
  • Scorre tutte le intestazioni del contenuto della risposta, scrivendo ognuna nella console.

Traccia HTTP

La TRACE richiesta può essere utile per il debug perché fornisce un loopback a livello di applicazione del messaggio di richiesta. Per effettuare una richiesta HTTP TRACE , creare un HttpRequestMessage oggetto usando HttpMethod.Trace:

using HttpRequestMessage request = new(
    HttpMethod.Trace, 
    "{ValidRequestUri}");

Attenzione

Il TRACE metodo HTTP non è supportato da tutti i server HTTP. Può esporre una vulnerabilità di sicurezza se usata senza senso. Per altre informazioni, vedere Open Web Application Security Project (OWASP): Cross Site Tracing.

Gestire una risposta HTTP

Ogni volta che si gestisce una risposta HTTP, si interagisce con il HttpResponseMessage tipo . Quando si valuta la validità di una risposta, vengono usati diversi membri. Il codice di stato HTTP è disponibile tramite la HttpResponseMessage.StatusCode proprietà . Si supponga di aver inviato una richiesta in base a un'istanza client:

using HttpResponseMessage response = await httpClient.SendAsync(request);

Per assicurarsi che response sia OK (codice di stato HTTP 200), è possibile valutarlo come illustrato nell'esempio seguente:

if (response is { StatusCode: HttpStatusCode.OK })
{
    // Omitted for brevity...
}

Esistono altri codici di stato HTTP che rappresentano una risposta corretta, ad esempio CREATED (codice di stato HTTP 201), ACCEPTED (codice di stato HTTP 202), NO CONTENT (codice di stato HTTP 204) e RESET CONTENT (codice di stato HTTP 205). È possibile usare la HttpResponseMessage.IsSuccessStatusCode proprietà per valutare anche questi codici, che garantisce che il codice di stato della risposta sia compreso nell'intervallo da 200 a 299:

if (response.IsSuccessStatusCode)
{
    // Omitted for brevity...
}

Se è necessario che il framework generi , HttpRequestExceptionè possibile chiamare il HttpResponseMessage.EnsureSuccessStatusCode() metodo :

response.EnsureSuccessStatusCode();

Questo codice genera un'eccezione HttpRequestException se il codice di stato della risposta non rientra nell'intervallo da 200 a 299.

Risposte di contenuto valide HTTP

Con una risposta valida, è possibile accedere al corpo della risposta usando la Content proprietà . Il corpo è disponibile come HttpContent istanza, che è possibile usare per accedere al corpo come flusso, matrice di byte o stringa:

await using Stream responseStream =
    await response.Content.ReadAsStreamAsync();

Nel codice precedente, responseStream può essere usato per leggere il corpo della risposta.

byte[] responseByteArray = await response.Content.ReadAsByteArrayAsync();

Nel codice precedente, responseByteArray può essere usato per leggere il corpo della risposta.

string responseString = await response.Content.ReadAsStringAsync();

Nel codice precedente, responseString può essere usato per leggere il corpo della risposta.

Infine, quando si conosce un endpoint HTTP restituisce JSON, è possibile deserializzare il corpo della risposta in qualsiasi oggetto C# valido usando il pacchetto NuGet System.Net.Http.Json :

T? result = await response.Content.ReadFromJsonAsync<T>();

Nel codice precedente è result il corpo della risposta deserializzato come tipo T.

Gestione degli errori HTTP

Quando una richiesta HTTP ha esito negativo, viene generata l'eccezione HttpRequestException . Intercettare l'eccezione da sola potrebbe non essere sufficiente, in quanto sono presenti altre potenziali eccezioni generate che è possibile prendere in considerazione la gestione. Ad esempio, il codice chiamante potrebbe aver usato un token di annullamento annullato prima del completamento della richiesta. In questo scenario si intercettare :TaskCanceledException

using var cts = new CancellationTokenSource();
try
{
    // Assuming:
    //   httpClient.Timeout = TimeSpan.FromSeconds(10)

    using var response = await httpClient.GetAsync(
        "http://localhost:5001/sleepFor?seconds=100", cts.Token);
}
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{
    // When the token has been canceled, it is not a timeout.
    Console.WriteLine($"Canceled: {ex.Message}");
}

Analogamente, quando si effettua una richiesta HTTP, se il server non risponde prima che venga superata la HttpClient.Timeout stessa eccezione viene generata. In questo scenario, tuttavia, è possibile distinguere che il timeout si è verificato valutando quando Exception.InnerException si intercetta :TaskCanceledException

try
{
    // Assuming:
    //   httpClient.Timeout = TimeSpan.FromSeconds(10)

    using var response = await httpClient.GetAsync(
        "http://localhost:5001/sleepFor?seconds=100");
}
catch (OperationCanceledException ex) when (ex.InnerException is TimeoutException tex)
{
    Console.WriteLine($"Timed out: {ex.Message}, {tex.Message}");
}

Nel codice precedente, quando l'eccezione interna è un TimeoutException timeout si è verificato e la richiesta non è stata annullata dal token di annullamento.

Per valutare il codice di stato HTTP quando si intercetta un HttpRequestExceptionoggetto , è possibile valutare la HttpRequestException.StatusCode proprietà :

try
{
    // Assuming:
    //   httpClient.Timeout = TimeSpan.FromSeconds(10)

    using var response = await httpClient.GetAsync(
        "http://localhost:5001/doesNotExist");

    response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
    // Handle 404
    Console.WriteLine($"Not found: {ex.Message}");
}

Nel codice precedente viene chiamato il EnsureSuccessStatusCode() metodo per generare un'eccezione se la risposta non riesce. La HttpRequestException.StatusCode proprietà viene quindi valutata per determinare se la risposta è un 404 (codice di stato HTTP 404). Esistono diversi metodi helper per HttpClient chiamare EnsureSuccessStatusCode in modo implicito per conto dell'utente, considerare le API seguenti:

Suggerimento

Tutti i HttpClient metodi usati per effettuare richieste HTTP che non restituiscono una HttpResponseMessage chiamata EnsureSuccessStatusCode implicita per conto dell'utente.

Quando si chiamano questi metodi, è possibile gestire e HttpRequestException valutare la HttpRequestException.StatusCode proprietà per determinare il codice di stato HTTP della risposta:

try
{
    // These extension methods will throw HttpRequestException
    // with StatusCode set when the HTTP request status code isn't 2xx:
    //
    //   GetByteArrayAsync
    //   GetStreamAsync
    //   GetStringAsync

    using var stream = await httpClient.GetStreamAsync(
        "https://localhost:5001/doesNotExists");
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
    // Handle 404
    Console.WriteLine($"Not found: {ex.Message}");
}

Potrebbero essere presenti scenari in cui è necessario generare l'eccezione HttpRequestException nel codice. Il HttpRequestException() costruttore è pubblico ed è possibile usarlo per generare un'eccezione con un messaggio personalizzato:

try
{
    using var response = await httpClient.GetAsync(
        "https://localhost:5001/doesNotExists");

    // Throw for anything higher than 400.
    if (response is { StatusCode: >= HttpStatusCode.BadRequest })
    {
        throw new HttpRequestException(
            "Something went wrong", inner: null, response.StatusCode);
    }
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
    Console.WriteLine($"Not found: {ex.Message}");
}

Proxy HTTP

Un proxy HTTP può essere configurato in due modi. Nella proprietà viene specificato HttpClient.DefaultProxy un valore predefinito. In alternativa, è possibile specificare un proxy nella HttpClientHandler.Proxy proprietà .

Proxy predefinito globale

HttpClient.DefaultProxy è una proprietà statica che determina il proxy predefinito usato da tutte le HttpClient istanze se non viene impostato alcun proxy in modo esplicito nel passato attraverso il HttpClientHandler relativo costruttore.

L'istanza predefinita restituita da questa proprietà inizializza un set di regole diverso a seconda della piattaforma:

  • Per Windows: legge la configurazione del proxy dalle variabili di ambiente o, se non sono definite, dalle impostazioni proxy dell'utente.
  • Per macOS: legge la configurazione del proxy dalle variabili di ambiente o, se non sono definite, dalle impostazioni proxy del sistema.
  • Per Linux: legge la configurazione del proxy dalle variabili di ambiente o, nel caso in cui non siano definite, questa proprietà inizializza un'istanza non configurata che ignora tutti gli indirizzi.

Le variabili di ambiente usate per DefaultProxy l'inizializzazione nelle piattaforme basate su Windows e Unix sono:

  • HTTP_PROXY: il server proxy usato nelle richieste HTTP.
  • HTTPS_PROXY: il server proxy usato nelle richieste HTTPS.
  • ALL_PROXY: il server proxy usato nelle richieste HTTP e/o HTTPS nel caso HTTP_PROXY e/o HTTPS_PROXY non sono definite.
  • NO_PROXY: elenco delimitato da virgole di nomi host che devono essere esclusi dal proxy. Gli asterischi non sono supportati per i caratteri jolly; usare un punto iniziale nel caso in cui si voglia trovare una corrispondenza con un sottodominio. Esempi: NO_PROXY=.example.com (con punto iniziale) corrisponderà www.example.coma , ma non corrisponderà example.coma . NO_PROXY=example.com (senza punto iniziale) non corrisponderà www.example.coma . Questo comportamento potrebbe essere rivisitato in futuro per trovare una corrispondenza migliore con altri ecosistemi.

Nei sistemi in cui le variabili di ambiente fanno distinzione tra maiuscole e minuscole, i nomi delle variabili possono essere tutti minuscoli o maiuscoli. I nomi minuscoli vengono prima controllati.

Il server proxy può essere un nome host o un indirizzo IP, seguito facoltativamente da due punti e da un numero di porta oppure può essere un http URL, facoltativamente includendo un nome utente e una password per l'autenticazione proxy. L'URL deve iniziare con http, non httpse non può includere testo dopo il nome host, l'IP o la porta.

Proxy per client

La HttpClientHandler.Proxy proprietà identifica l'oggetto WebProxy da utilizzare per elaborare le richieste alle risorse Internet. Per specificare che non deve essere usato alcun proxy, impostare la Proxy proprietà sull'istanza proxy restituita dal GlobalProxySelection.GetEmptyWebProxy() metodo .

Il computer locale o il file di configurazione dell'applicazione può specificare che viene usato un proxy predefinito. Se si specifica la proprietà Proxy, le impostazioni proxy della proprietà Proxy sostituiscono il computer locale o il file di configurazione dell'applicazione e il gestore usa le impostazioni proxy specificate. Se non viene specificato alcun proxy in un file di configurazione e la proprietà Proxy non è specificata, il gestore usa le impostazioni proxy ereditate dal computer locale. Se non sono presenti impostazioni proxy, la richiesta viene inviata direttamente al server.

La HttpClientHandler classe analizza un elenco di bypass proxy con caratteri jolly ereditati dalle impostazioni del computer locale. Ad esempio, la HttpClientHandler classe analizza un elenco di bypass di "nt*" dai browser come espressione regolare di "nt.*". Quindi, un URL di http://nt.com ignora il proxy usando la HttpClientHandler classe .

La HttpClientHandler classe supporta il bypass proxy locale. La classe considera una destinazione locale se vengono soddisfatte una delle condizioni seguenti:

  1. La destinazione contiene un nome flat (nessun punto nell'URL).
  2. La destinazione contiene un indirizzo di loopback (Loopback o IPv6Loopback) o la destinazione contiene un oggetto IPAddress assegnato al computer locale.
  3. Il suffisso di dominio della destinazione corrisponde al suffisso di dominio del computer locale (DomainName).

Per altre informazioni sulla configurazione di un proxy, vedere:

Vedi anche