Partager via


Effectuer des requêtes HTTP avec la classe HttpClient

Dans cet article, vous allez apprendre à effectuer des requêtes HTTP et à gérer des réponses avec la classe HttpClient.

Importante

Tous les exemples de requêtes HTTP de cet article ciblent l’une des URL suivantes :

Les points de terminaison HTTP retournent généralement des données JSON (JavaScript Object Notation), mais pas toujours. Pour plus de commodité, le package NuGet System.Net.Http.Json facultatif fournit plusieurs méthodes d’extension pour les objets HttpClient et HttpContent qui effectuent la sérialisation et la désérialisation automatiques à l’aide du package NuGet 📦 System.Text.Json. Les exemples de cet article appellent l’attention sur les emplacements où ces extensions sont disponibles.

Conseil

Tout le code source référencé dans cet article est disponible dans le dépôt GitHub : .NET Docs.

Créer un objet HttpClient

La plupart des exemples de cet article réutilisent la même instance de HttpClient. Vous pouvez donc configurer l’instance une seule fois et l’utiliser pour les exemples restants. Pour créer un objet HttpClient, utilisez le constructeur de classe HttpClient. Pour plus d’informations, consultez Instructions relatives à l’utilisation de 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"),
};

Le code effectue les tâches suivantes :

  • Instanciez une nouvelle instance de HttpClient en tant que variable static. Selon les instructions , l’approche recommandée consiste à réutiliser HttpClient instances pendant le cycle de vie de l’application.
  • Définissez la propriété HttpClient.BaseAddress sur "https://jsonplaceholder.typicode.com".

Cette instance HttpClient utilise l’adresse de base pour effectuer des requêtes ultérieures. Pour appliquer d’autres configurations, tenez compte des API suivantes :

Conseil

Vous pouvez également créer des instances HttpClient à l’aide d’une approche de modèle de fabrique qui vous permet de configurer n’importe quel nombre de clients et de les consommer en tant que services d’injection de dépendances. Pour plus d’informations, consultez Fabrique de client HTTP avec .NET.

Effectuer une requête HTTP

Pour effectuer une requête HTTP, vous appelez l’une des méthodes d’API suivantes :

HTTP method Interface de Programmation d'Applications (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

demande de USER SPECIFIED indique que la méthode SendAsync accepte tout objet HttpMethod valide.

Avertissement

L’envoi de requêtes HTTP est considéré comme un travail lié aux E/S réseau. Une méthode de HttpClient.Send synchrone existe, mais la recommandation consiste à utiliser les API asynchrones à la place, sauf si vous avez une bonne raison de ne pas le faire.

Remarque

Lors du ciblage d’appareils Android (par exemple, avec le développement MAUI .NET), vous devez ajouter la définition android:usesCleartextTraffic="true" à la section <application></application> dans le fichier AndroidManifest.xml. Ce paramètre active le trafic en texte clair, tel que les requêtes HTTP, qui est sinon désactivée par défaut en raison de stratégies de sécurité Android. Par exemple, prenez les paramètres XML suivants :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <application android:usesCleartextTraffic="true"></application>
  <!-- omitted for brevity -->
</manifest>

Pour plus d’informations, veuillez consulter Activation du trafic réseau en texte clair pour le domaine localhost.

Comprendre le contenu HTTP

Le type HttpContent est utilisé pour représenter un corps d’entité HTTP et les en-têtes de contenu correspondants. Pour les méthodes HTTP (ou méthodes de requête) qui nécessitent un corps (POST, PUT, PATCH), vous utilisez la classe HttpContent pour spécifier le corps de la requête. La plupart des exemples montrent comment préparer la sous-classe StringContent avec une charge utile JSON, mais d’autres sous-classes existent pour différents types de contenu (MIME).

La classe HttpContent est également utilisée pour représenter le corps de réponse de la classe HttpResponseMessage, accessible sur la propriété HttpResponseMessage.Content.

Utiliser une requête HTTP GET

Une requête GET ne doit pas envoyer de contenu. Cette requête est utilisée (comme le nom de la méthode indique) pour récupérer (ou obtenir) des données d’une ressource. Pour effectuer une requête HTTP GET en fonction d’une instance de HttpClient et d’un objet Uri, utilisez la méthode HttpClient.GetAsync :

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
    //   }
}

Le code effectue les tâches suivantes :

  • Envoyez une requête GET au point de terminaison "https://jsonplaceholder.typicode.com/todos/3".
  • Vérifiez que la réponse réussit.
  • Écrivez les détails de la demande dans la console.
  • Lisez le corps de réponse comme une chaîne.
  • Écrivez le corps de la réponse JSON dans la console.

La méthode WriteRequestToConsole est une extension personnalisée qui ne fait pas partie de l’infrastructure. Si vous êtes curieux de l’implémentation, tenez compte du code C# suivant :

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}");        
    }
}

Cette fonctionnalité est utilisée pour écrire les détails de la demande dans la console sous la forme suivante :

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

Par exemple, la requête GET au point de terminaison "https://jsonplaceholder.typicode.com/todos/3" génère le message suivant :

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

Créer la requête HTTP GET à partir de JSON

Le point de terminaison https://jsonplaceholder.typicode.com/todos retourne un tableau JSON d’objets Todo. Leur structure JSON ressemble au formulaire suivant :

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

L'objet Todo C# est défini comme suit :

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

Il s’agit d’un type record class, avec des propriétés facultatives Id, Title, Completed et UserId. Pour plus d’informations sur le type record, consultez Présentation des types d’enregistrement en C#. Pour désérialiser automatiquement les requêtes GET en un objet C# fortement typé, utilisez la méthode d'extension GetFromJsonAsync, qui fait partie du package 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 }
}

Le code effectue les tâches suivantes :

  • Envoyez une requête GET à "https://jsonplaceholder.typicode.com/todos?userId=1&completed=false".

    La chaîne de requête représente les critères de filtrage de la requête. Lorsque la commande réussit, la réponse est automatiquement désérialisée dans un objet List<Todo>.

  • Écrivez les détails de la requête dans la console, ainsi que chaque objet Todo.

Utiliser une requête HTTP POST

Une requête POST envoie des données au serveur pour traitement. L’en-tête Content-Type de la demande indique le type MIME que le corps envoie. Pour effectuer une requête HTTP POST en fonction d’une instance de HttpClient et d’un objet Uri, utilisez la méthode HttpClient.PostAsync :

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
    //   }
}

Le code effectue les tâches suivantes :

  • Préparez une instance StringContent avec le corps JSON de la requête (type MIME de "application/json").
  • Envoyez une requête POST au point de terminaison "https://jsonplaceholder.typicode.com/todos".
  • Vérifiez que la réponse réussit et écrivez les détails de la demande dans la console.
  • Écrivez le corps de la réponse sous forme de chaîne dans la console.

Créer la requête HTTP POST en tant que JSON

Pour sérialiser automatiquement les arguments de requête POST et désérialiser les réponses en objets C# fortement typés, utilisez la méthode d’extension PostAsJsonAsync qui fait partie du package 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 }
}

Le code effectue les tâches suivantes :

  • Sérialisez l’instance Todo en tant que JSON et effectuez une requête POST au point de terminaison "https://jsonplaceholder.typicode.com/todos".
  • Vérifiez que la réponse réussit et écrivez les détails de la demande dans la console.
  • Désérialisez le corps de la réponse dans une instance Todo et écrivez l’objet Todo dans la console.

Utiliser une requête HTTP PUT

La méthode de requête PUT remplace une ressource existante ou en crée une nouvelle à l’aide de la charge utile du corps de la requête. Pour effectuer une requête HTTP PUT en fonction d’une instance de HttpClient et d’un objet Uri, utilisez la méthode HttpClient.PutAsync :

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
    //   }
}

Le code effectue les tâches suivantes :

  • Préparez une instance StringContent avec le corps JSON de la requête (type MIME de "application/json").
  • Envoyez une requête PUT au point de terminaison "https://jsonplaceholder.typicode.com/todos/1".
  • Vérifiez que la réponse réussit et écrivez les détails de la requête avec le corps de la réponse JSON dans la console.

Créer la requête HTTP PUT en tant que JSON

Pour sérialiser automatiquement les arguments de requête PUT et désérialiser les réponses en objets C# fortement typés, utilisez la méthode d’extension PutAsJsonAsync qui fait partie du package 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 }
}

Le code effectue les tâches suivantes :

  • Sérialisez l’instance Todo en tant que JSON et effectuez une requête PUT au point de terminaison "https://jsonplaceholder.typicode.com/todos/5".
  • Vérifiez que la réponse réussit et écrivez les détails de la demande dans la console.
  • Désérialisez le corps de la réponse dans une instance Todo et écrivez les objets Todo dans la console.

Utiliser une requête HTTP PATCH

La requête PATCH est une mise à jour partielle d’une ressource existante. Cette requête ne crée pas de ressource et n’est pas destinée à remplacer une ressource existante. Au lieu de cela, cette méthode met uniquement à jour partiellement une ressource. Pour effectuer une requête HTTP PATCH en fonction d’une instance de HttpClient et d’un objet Uri, utilisez la méthode HttpClient.PatchAsync :

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
    //   }
}

Le code effectue les tâches suivantes :

  • Préparez une instance StringContent avec le corps JSON de la requête (type MIME de "application/json").
  • Envoyez une requête PATCH au point de terminaison "https://jsonplaceholder.typicode.com/todos/1".
  • Vérifiez que la réponse réussit et écrivez les détails de la requête avec le corps de la réponse JSON dans la console.

Il n’existe aucune méthode d’extension pour les requêtes PATCH dans le package NuGet System.Net.Http.Json.

Utiliser une requête HTTP DELETE

Une requête DELETE supprime une ressource existante et elle est idempotente, mais pas sécurisée. Plusieurs requêtes DELETE aux mêmes ressources produisent le même résultat, mais la requête affecte l’état de la ressource. Pour effectuer une requête HTTP DELETE en fonction d’une instance de HttpClient et d’un objet Uri, utilisez la méthode HttpClient.DeleteAsync :

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
    //   {}
}

Le code effectue les tâches suivantes :

  • Envoyez une requête DELETE au point de terminaison "https://jsonplaceholder.typicode.com/todos/1".
  • Vérifiez que la réponse réussit et écrivez les détails de la demande dans la console.

Conseil

La réponse à une requête de DELETE (comme une requête de PUT) peut inclure ou non un contenu.

Explorer la requête HTTP HEAD

La requête HEAD est similaire à une requête GET. Au lieu de retourner la ressource, cette requête retourne uniquement les en-têtes associés à la ressource. Une réponse à la requête HEAD ne retourne pas de contenu. Pour effectuer une requête HTTP HEAD en fonction d’une instance de HttpClient et d’un objet Uri, utilisez la méthode HttpClient.SendAsync avec le type de HttpMethod défini sur 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
}

Le code effectue les tâches suivantes :

  • Effectuez une requête HEAD à l'endpoint "https://www.example.com/".
  • Vérifiez que la réponse réussit et écrivez les détails de la demande dans la console.
  • Effectuez une itération sur tous les en-têtes de réponse et écrivez chaque en-tête dans la console.

Explorer la requête HTTP OPTIONS

La requête OPTIONS est utilisée pour identifier les méthodes HTTP prises en charge par un serveur ou un point de terminaison. Pour effectuer une requête HTTP OPTIONS en fonction d’une instance de HttpClient et d’un objet Uri, utilisez la méthode HttpClient.SendAsync avec le type de HttpMethod défini sur 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
}

Le code effectue les tâches suivantes :

  • Envoyez une requête HTTP OPTIONS au point de terminaison "https://www.example.com/".
  • Vérifiez que la réponse réussit et écrivez les détails de la demande dans la console.
  • Effectuez une itération sur tous les en-têtes de contenu de réponse et écrivez chaque en-tête dans la console.

Explorer la requête HTTP TRACE

La requête TRACE peut être utile pour le débogage, car elle fournit une boucle arrière au niveau de l’application du message de requête. Pour effectuer une requête http TRACE, créez une HttpRequestMessage à l’aide du type HttpMethod.Trace :

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

Attention

Tous les serveurs HTTP ne prennent pas en charge la méthode HTTP TRACE. Cette méthode peut exposer une vulnérabilité de sécurité si elle est utilisée sans sens. Pour plus d’informations, consultez Open Web Application Security Project (OWASP) : suivi intersite.

Gérer une réponse HTTP

Lorsque vous gérez une réponse HTTP, vous interagissez avec le type de HttpResponseMessage. Plusieurs membres sont utilisés pour évaluer la validité d’une réponse. Le code d’état HTTP est disponible dans la propriété HttpResponseMessage.StatusCode.

Supposons que vous envoyez une demande donnée à une instance cliente :

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

Pour vous assurer que la response est OK (code d’état HTTP 200), vous pouvez évaluer la valeur comme indiqué dans l’exemple suivant :

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

Il existe d’autres codes d’état HTTP qui représentent une réponse réussie, tels que CREATED (code d’état HTTP 201), ACCEPTED (code d’état HTTP 202), NO CONTENT (code d’état HTTP 204) et RESET CONTENT (code d’état HTTP 205). Vous pouvez également utiliser la propriété HttpResponseMessage.IsSuccessStatusCode pour évaluer ces codes, ce qui garantit que le code d’état de la réponse se trouve dans la plage 200-299 :

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

Si vous avez besoin que l’infrastructure lève l’erreur HttpRequestException, vous pouvez appeler la méthode HttpResponseMessage.EnsureSuccessStatusCode() :

response.EnsureSuccessStatusCode();

Ce code génère une erreur HttpRequestException si le code d’état de la réponse n’est pas compris dans la plage 200-299.

Explorer les réponses de contenu valides HTTP

Avec une réponse valide, vous pouvez accéder au corps de la réponse à l’aide de la propriété Content. Le corps est disponible en tant qu’instance HttpContent, que vous pouvez utiliser pour accéder au corps en tant que flux, tableau d’octets ou chaîne.

Le code suivant utilise l’objet responseStream pour lire le corps de la réponse :

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

Vous pouvez utiliser différents objets pour lire le corps de la réponse. Utilisez l’objet responseByteArray pour lire le corps de la réponse :

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

Utilisez l’objet responseString pour lire le corps de la réponse :

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

Lorsque vous connaissez un point de terminaison HTTP retourne JSON, vous pouvez désérialiser le corps de la réponse dans n’importe quel objet C# valide à l’aide du package NuGet System.Net.Http.Json :

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

Dans ce code, la valeur result est le corps de la réponse désérialisé en tant que type T.

Utiliser la gestion des erreurs HTTP

Lorsqu’une requête HTTP échoue, le système lève l’objet HttpRequestException. L’interception de l’exception seule peut ne pas suffire. Il existe d’autres exceptions potentielles levées que pourriez envisager de gérer. Par exemple, le code appelant peut utiliser un jeton d’annulation qui a été annulé avant la fin de la demande. Dans ce scénario, vous pouvez intercepter l’erreur 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}");
}

De même, lorsque vous effectuez une requête HTTP, si le serveur ne répond pas avant que la valeur de HttpClient.Timeout soit dépassée, la même exception est levée. Dans ce scénario, vous pouvez distinguer que le délai d’expiration s’est produit en évaluant la propriété Exception.InnerException lors de la capture de l’erreur 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}");
}

Dans le code, lorsque l’exception interne est un type TimeoutException, le délai d’attente s’est produit et le jeton d’annulation n’annule pas la requête.

Pour évaluer le code d’état HTTP lorsque vous interceptez l’objet HttpRequestException, vous pouvez évaluer la propriété HttpRequestException.StatusCode :

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}");
}

Dans le code, la méthode EnsureSuccessStatusCode() est appelée pour lever une exception si la réponse n’a pas réussi. La propriété HttpRequestException.StatusCode est ensuite évaluée pour déterminer si la réponse était un 404 (code d’état HTTP 404). Il existe plusieurs méthodes d’assistance sur l’objet HttpClient qui appellent implicitement la méthode EnsureSuccessStatusCode en votre nom.

Pour la gestion d’erreurs HTTP, tenez compte des API suivantes :

Conseil

Toutes les méthodes HttpClient utilisées pour effectuer des requêtes HTTP qui ne retournent pas de type HttpResponseMessage appellent implicitement la méthode EnsureSuccessStatusCode en votre nom.

Lorsque vous appelez ces méthodes, vous pouvez gérer l’objet HttpRequestException et évaluer la propriété HttpRequestException.StatusCode pour déterminer le code d’état HTTP de la réponse :

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}");
}

Il peut y avoir des scénarios où vous devez générer l’objet HttpRequestException dans votre code. Le constructeur HttpRequestException() est public et vous pouvez l’utiliser pour lever une exception avec un message personnalisé :

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}");
}

Configurer un proxy HTTP

Un proxy HTTP peut être configuré de l’une des deux façons suivantes. Une valeur par défaut est spécifiée sur la propriété HttpClient.DefaultProxy. Vous pouvez également spécifier un proxy sur la propriété HttpClientHandler.Proxy.

Utiliser un proxy par défaut global

La propriété HttpClient.DefaultProxy est une propriété statique qui détermine le proxy par défaut utilisé par toutes les instances HttpClient, si aucun proxy n’est défini explicitement dans l’objet HttpClientHandler passé par son constructeur.

L’instance par défaut retournée par cette propriété initialise en fonction d’un ensemble de règles différent en fonction de votre plateforme :

  • Windows: lire la configuration du proxy à partir des variables d’environnement, ou si les variables ne sont pas définies, lire à partir des paramètres du proxy utilisateur.
  • macOS: lire la configuration du proxy à partir de variables d’environnement, ou si les variables ne sont pas définies, lues à partir des paramètres de proxy système.
  • Linux: lire la configuration du proxy à partir de variables d’environnement, ou si les variables ne sont pas définies, initialisez une instance non configurée pour contourner toutes les adresses.

L’initialisation de propriété DefaultProxy sur les plateformes Windows et Unix utilise les variables d’environnement suivantes :

  • HTTP_PROXY: serveur proxy utilisé sur les requêtes HTTP.
  • HTTPS_PROXY: serveur proxy utilisé sur les requêtes HTTPS.
  • ALL_PROXY: le serveur proxy utilisé sur les requêtes HTTP et/ou HTTPS lorsque les variables HTTP_PROXY et/ou HTTPS_PROXY ne sont pas définies.
  • NO_PROXY: liste séparée par des virgules de noms d’hôte à exclure du proxy. Les astérisques ne sont pas pris en charge lorsqu’ils sont utilisés comme caractères génériques. Utilisez une période de début (.) lorsque vous souhaitez faire correspondre un sous-domaine. Exemples : NO_PROXY=.example.com (avec période de début) correspond à www.example.com, mais ne correspond pas à example.com. NO_PROXY=example.com (sans période de début) ne correspond pas à www.example.com. Ce comportement peut être revisité à l’avenir pour mieux correspondre à d’autres écosystèmes.

Sur les systèmes où les variables d’environnement sont sensibles à la casse, les noms des variables peuvent être tout en minuscules ou tout en minuscules. Les noms en minuscules sont vérifiés en premier.

Le serveur proxy peut être un nom d’hôte ou une adresse IP, éventuellement suivi d’un signe deux-points et d’un numéro de port, ou il peut s’agir d’une URL http, y compris éventuellement un nom d’utilisateur et un mot de passe pour l’authentification proxy. L’URL doit commencer par http, pas httpset ne peut pas inclure de texte après le nom d’hôte, l’adresse IP ou le port.

Configurer le proxy par client

La propriété HttpClientHandler.Proxy identifie l’objet WebProxy à utiliser pour traiter les demandes adressées aux ressources Internet. Pour spécifier qu’aucun proxy ne doit être utilisé, définissez la propriété Proxy sur l’instance de proxy retournée par la méthode GlobalProxySelection.GetEmptyWebProxy().

Le fichier de configuration de l’ordinateur local ou de l’application peut spécifier qu’un proxy par défaut est utilisé. Si la propriété Proxy est spécifiée, les paramètres proxy de la propriété Proxy remplacent l’ordinateur local ou le fichier de configuration de l’application et le gestionnaire utilise les paramètres de proxy spécifiés. Si aucun proxy n’est spécifié dans un fichier de configuration et que la propriété Proxy n’est pas spécifiée, le gestionnaire utilise les paramètres de proxy hérités de l’ordinateur local. S’il n’existe aucun paramètre de proxy, la demande est envoyée directement au serveur.

La classe HttpClientHandler analyse une liste de contournement de proxy avec des caractères génériques hérités des paramètres de l’ordinateur local. Par exemple, la classe HttpClientHandler analyse une liste de contournement de "nt*" depuis des navigateurs en tant qu’expression régulière de "nt.*". Par conséquent, une URL de http://nt.com contourne le proxy à l’aide de la classe HttpClientHandler.

La classe HttpClientHandler prend en charge la déviation du proxy local. La classe considère qu’une destination est locale si l’une des conditions suivantes est remplie :

  • La destination contient un nom plat (aucun point (.) dans l’URL).
  • La destination contient une adresse de bouclage (Loopback ou IPv6Loopback) ou la destination contient une propriété IPAddress affectée à l’ordinateur local.
  • Le suffixe de domaine de la destination correspond au suffixe de domaine de l’ordinateur local, tel que défini dans la propriété DomainName.

Pour plus d’informations sur la configuration d’un proxy, consultez les API suivantes :

Étapes suivantes