Effectuer des requêtes HTTP avec la classe HttpClient
Dans cet article, vous allez apprendre à effectuer des requêtes HTTP et à gérer les réponses avec la classe HttpClient
.
Important
Tous les exemples de requêtes HTTP ciblent l’une des URL suivantes :
- https://jsonplaceholder.typicode.com : API factice gratuite pour le test et le prototypage.
- https://www.example.com : ce domaine est destiné à être utilisé dans des exemples d’illustration dans des documents.
Les points de terminaison HTTP retournent généralement des données JSON (JavaScript Object Notation), mais pas toujours. Par souci de commodité, le package NuGet System.Net.Http.Json facultatif fournit plusieurs méthodes d’extension pour HttpClient
et HttpContent
qui effectuent la sérialisation automatique et la désérialisation à l’aide de System.Text.Json
. Les exemples qui suivent attirent l’attention sur les emplacements où ces extensions sont disponibles.
Conseil
Tout le code source de cet article est disponible dans le référentiel GitHub : .NET Docs.
Créer un HttpClient
La plupart des exemples suivants utilisent la même instance HttpClient
et ne doivent donc être configurés qu’une seule fois. Pour créer un HttpClient
, utilisez le constructeur de classe HttpClient
. Pour plus d’informations, consultez Instructions relatives à l’utilisation de HttpClient.
// HttpClient lifecycle management best practices:
// https://video2.skills-academy.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
private static HttpClient sharedClient = new()
{
BaseAddress = new Uri("https://jsonplaceholder.typicode.com"),
};
Le code précédent :
- Instancie une nouvelle instance
HttpClient
en tant que variablestatic
. Conformément aux lignes directrices, il est vivement recommandé de réutiliser les instancesHttpClient
pendant le cycle de vie de l’application. - Définit le HttpClient.BaseAddress sur
"https://jsonplaceholder.typicode.com"
.
Cette instance HttpClient
utilise toujours l’adresse de base lors des requêtes suivantes. Pour appliquer une autre configuration, envisagez :
- De configurer HttpClient.DefaultRequestHeaders.
- d’appliquer une valeur autre que la valeur par défaut HttpClient.Timeout.
- De spécifier le HttpClient.DefaultRequestVersion.
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 API suivantes :
HTTP method | 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 |
†Une requête
USER SPECIFIED
indique que la méthodeSendAsync
accepte n’importe quelle valeur HttpMethod valide.
Avertissement
L’envoi de requêtes HTTP est considéré comme un travail lié aux E/S réseau. Bien qu’il existe une méthode HttpClient.Send synchrone, il est recommandé d’utiliser les API asynchrones à la place, sauf si vous avez de bonnes raisons de ne pas le faire.
Remarque
Lors du ciblage d’appareils Android (par exemple, avec le développement MAUI .NET), vous devez ajouter android:usesCleartextTraffic="true"
à <application></application>
dans AndroidManifest.xml. Cela active le trafic en texte clair, tel que les requêtes HTTP, qui est sinon désactivé 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.
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
et 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).
- ByteArrayContent : fournit un contenu HTTP basé sur un tableau d'octets.
- FormUrlEncodedContent : fournit du contenu HTTP pour les tuples nom/valeur encodés à l’aide du type MIME
"application/x-www-form-urlencoded"
. - JsonContent : fournit du contenu HTTP basé JSON.
- MultipartContent : fournit une collection d’objets HttpContent qui sont sérialisés à l’aide de la spécification de type MIME
"multipart/*"
. - MultipartFormDataContent : fournit un conteneur pour le contenu codé à l'aide du type MIME
"multipart/form-data"
. - ReadOnlyMemoryContent : fournit du contenu HTTP basé sur un ReadOnlyMemory<T>.
- StreamContent : fournit un contenu HTTP basé sur un flux.
- StringContent : dournit un contenu HTTP basé sur une chaîne.
La HttpContent
classe est également utilisée pour représenter le corps de la réponse du HttpResponseMessage, accessible sur la propriété HttpResponseMessage.Content.
HTTP Get
Une requête GET
ne doit pas envoyer de corps et est utilisée (comme le nom de la méthode l’indique) pour récupérer (ou obtenir) des données d’une ressource. Pour effectuer une requête HTTP GET
, en fonction d’un HttpClient
et d’un 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 précédent :
- Effectue une demande
GET
à"https://jsonplaceholder.typicode.com/todos/3"
. - Garantit que la réponse réussit.
- Écrit les détails de la demande dans la console.
- Lit le corps de réponse comme une chaîne.
- Écrit le corps de la réponse JSON dans la console.
WriteRequestToConsole
est une méthode d’extension personnalisée qui ne fait pas partie de l’infrastructure, mais si vous êtes curieux de savoir comment elle est implémentée, considérez le 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 demande GET
pour https://jsonplaceholder.typicode.com/todos/3
émet le message suivant :
GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1
HTTP Get à partir de JSON
Le point de terminaison https://jsonplaceholder.typicode.com/todos retourne un tableau JSON d’objets « todo ». La structure JSON se présente de la façon suivante :
[
{
"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 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 }
}
Dans le code précédent :
GET
Une demande est adressée à"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.
- La réponse est automatiquement désérialisée dans un
List<Todo>
en cas de réussite. - Les détails de la demande sont écrits dans la console, ainsi que chaque objet
Todo
.
Publication HTTP
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 POST
HTTP, en fonction d’un HttpClient
et d’un 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 précédent :
- Prépare une instance StringContent avec le corps JSON de la requête (type MIME de
"application/json"
). - Adresse une demande
POST
à"https://jsonplaceholder.typicode.com/todos"
. - Vérifie que la réponse est réussie et écrit les détails de la demande dans la console.
- Écrit le corps de la réponse sous forme de chaîne dans la console.
Publication HTTP 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 précédent :
- Sérialise l’instance
Todo
au format JSON et envoie une requêtePOST
à"https://jsonplaceholder.typicode.com/todos"
. - Vérifie que la réponse est réussie et écrit les détails de la demande dans la console.
- Désérialise le corps de la réponse dans une instance
Todo
et écrit leTodo
dans la console.
Put HTTP
La méthode de requête PUT
remplace une ressource existante ou en crée une à l’aide de la charge utile du corps de la requête. Pour effectuer une requête PUT
HTTP, en fonction d’un HttpClient
et d’un 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 précédent :
- Prépare une instance StringContent avec le corps JSON de la requête (type MIME de
"application/json"
). - Adresse une demande
PUT
à"https://jsonplaceholder.typicode.com/todos/1"
. - Vérifie que la réponse est réussie et écrit les détails de la demande et un corps de réponse JSON dans la console.
Put HTTP 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 précédent :
- Sérialise l’instance
Todo
au format JSON et envoie une requêtePUT
à"https://jsonplaceholder.typicode.com/todos/5"
. - Vérifie que la réponse est réussie et écrit les détails de la demande dans la console.
- Désérialise le corps de la réponse dans une instance
Todo
et écrit leTodo
dans la console.
Correctif HTTP
La requête PATCH
est une mise à jour partielle d’une ressource existante. Elle ne crée pas de ressource et n’est pas destinée à remplacer une ressource existante. Au lieu de cela, il ne met à jour une ressource que partiellement. Pour effectuer une requête PATCH
HTTP, en fonction d’un HttpClient
et d’un 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 précédent :
- Prépare une instance StringContent avec le corps JSON de la requête (type MIME de
"application/json"
). - Adresse une demande
PATCH
à"https://jsonplaceholder.typicode.com/todos/1"
. - Vérifie que la réponse est réussie et écrit les détails de la demande et un corps de 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
.
Supprimer HTTP
Une requête DELETE
supprime une ressource existante. Une requête DELETE
est idempotente, mais non sécurisée, ce qui signifie que plusieurs requêtes DELETE
adressées aux mêmes ressources produisent le même résultat, mais que la demande affecte l’état de la ressource. Pour effectuer une requête HTTP DELETE
, en fonction d’un HttpClient
et d’un 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 précédent :
- Adresse une demande
DELETE
à"https://jsonplaceholder.typicode.com/todos/1"
. - Vérifie que la réponse est réussie et écrit les détails de la demande dans la console.
Conseil
La réponse à une requête DELETE
(tout comme une requête PUT
) peut inclure ou non un corps.
Tête HTTP
La requête HEAD
est similaire à une requête GET
. Au lieu de retourner la ressource, il retourne uniquement les en-têtes associés à la ressource. Une réponse à la requête HEAD
ne retourne pas de corps. Pour effectuer une requête HEAD
HTTP, en fonction d’un HttpClient
et d’un URI, utilisez la méthode HttpClient.SendAsync avec la 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 précédent :
- Adresse une demande
HEAD
à"https://www.example.com/"
. - Vérifie que la réponse est réussie et écrit les détails de la demande dans la console.
- Itère sur tous les en-têtes de réponse, en écrivant chacun dans la console.
Options HTTP
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 OPTIONS
HTTP, en fonction d’un HttpClient
et d’un URI, utilisez la méthode HttpClient.SendAsync avec la 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 précédent :
- Envoie une requête
OPTIONS
HTTP à"https://www.example.com/"
. - Vérifie que la réponse est réussie et écrit les détails de la demande dans la console.
- Itère sur tous les en-têtes de contenu de réponse, en écrivant chacun dans la console.
Trace HTTP
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 de HttpMethod.Trace
:
using HttpRequestMessage request = new(
HttpMethod.Trace,
"{ValidRequestUri}");
Attention
La méthode HTTP TRACE
n’est pas prise en charge par tous les serveurs HTTP. Elle peut exposer une vulnérabilité de sécurité si elle est utilisé de manière imprudente. Pour plus d’informations, consultez Open Web Application Security Project (OWASP) : suivi intersite.
Gérer une réponse HTTP
Chaque fois que vous gérez une réponse HTTP, vous interagissez avec le type HttpResponseMessage. Plusieurs membres sont utilisés lors de l’évaluation de la validité d’une réponse. Le code d’état HTTP est disponible via la propriété HttpResponseMessage.StatusCode. Imaginez que vous avez envoyé une requête à une instance cliente :
using HttpResponseMessage response = await httpClient.SendAsync(request);
Pour vous assurer que response
est OK
(code d’état HTTP 200), vous pouvez l’évaluer 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 le HttpRequestException, vous pouvez appeler la méthode HttpResponseMessage.EnsureSuccessStatusCode() :
response.EnsureSuccessStatusCode();
Ce code lève une HttpRequestException
si le code d’état de la réponse ne se trouve pas dans la plage 200-299.
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 sous la forme d’un flux, d’un tableau d’octets ou d’une chaîne :
await using Stream responseStream =
await response.Content.ReadAsStreamAsync();
Dans le code précédent, le responseStream
peut être utilisé pour lire le corps de la réponse.
byte[] responseByteArray = await response.Content.ReadAsByteArrayAsync();
Dans le code précédent, le responseByteArray
peut être utilisé pour lire le corps de la réponse.
string responseString = await response.Content.ReadAsStringAsync();
Dans le code précédent, le responseString
peut être utilisé pour lire le corps de la réponse.
Enfin, quand vous savez qu’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 le code précédent, result
est le corps de la réponse désérialisé en tant que type T
.
Gestion des erreurs HTTP
Lorsqu’une requête HTTP échoue, la HttpRequestException est levée. La détection de cette exception seule peut ne pas suffire, car il existe d’autres exceptions potentielles levées que vous souhaiterez peut-être gérer. Par exemple, le code appelant peut avoir utilisé un jeton d’annulation qui a été annulé avant la fin de la demande. Dans ce scénario, vous interceptez :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 le HttpClient.Timeout est dépassé, la même exception est levée. Toutefois, dans ce scénario, vous pouvez distinguer que le délai d’expiration s’est produit en évaluant le Exception.InnerException lors de la capture de 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 précédent, lorsque l’exception interne est une exception, le délai d’expiration TimeoutException s’est produit et la demande n’a pas été annulée par le jeton d’annulation.
Pour évaluer le code d’état HTTP lors de la capture d’un 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 précédent, la méthode EnsureSuccessStatusCode() est appelée pour lever une exception si la réponse échoue. 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 HttpClient
qui appellent EnsureSuccessStatusCode
implicitement en votre nom, considérez les API suivantes :
Conseil
Toutes les méthodes HttpClient
utilisées pour effectuer des requêtes HTTP qui ne retournent pas HttpResponseMessage
appellent implicitement EnsureSuccessStatusCode
en votre nom.
Lorsque vous appelez ces méthodes, vous pouvez gérer le 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 dans lesquels vous devez lever le 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}");
}
Serveur 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.
Proxy global par défaut
HttpClient.DefaultProxy
est une propriété statique qui détermine le proxy par défaut que toutes les instances HttpClient
utilisent si aucun proxy n’est défini explicitement dans le HttpClientHandler passé via son constructeur.
L’instance par défaut retournée par cette propriété s’initialise selon un ensemble différent de règles en fonction de votre plateforme :
- Pour Windows : lit la configuration du proxy à partir de variables d’environnement ou, si celles-ci ne sont pas définies, à partir des paramètres de proxy de l’utilisateur.
- Pour macOS : lit la configuration du proxy à partir de variables d’environnement ou, si celles-ci ne sont pas définies, à partir des paramètres de proxy du système.
- Pour Linux : lit la configuration du proxy à partir de variables d’environnement ou, si celles-ci ne sont pas définies, cette propriété initialise une instance non configurée qui contourne toutes les adresses.
Les variables d’environnement utilisées pour l’initialisation de DefaultProxy
sur les plateformes Windows et Unix sont les suivantes :
HTTP_PROXY
: serveur proxy utilisé sur les demandes HTTP.HTTPS_PROXY
: serveur proxy utilisé sur les demandes HTTPS.ALL_PROXY
: le serveur proxy utilisé sur les requêtes HTTP et/ou HTTPS dans le casHTTP_PROXY
et/ouHTTPS_PROXY
ne sont pas définis.NO_PROXY
: liste de noms d’hôte séparés par des virgules à exclure comme proxy. Les astérisques ne sont pas pris en charge pour les caractères génériques ; utilisez un point de début au cas où vous souhaitez faire correspondre un sous-domaine. Exemples :NO_PROXY=.example.com
(avec point de début) correspond àwww.example.com
, mais ne correspond pas àexample.com
.NO_PROXY=example.com
(sans point 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
et non par https
et ne peut pas inclure de texte après le nom d’hôte, l’adresse IP ou le port.
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().
L’ordinateur local ou le fichier config de l’application peut spécifier qu’un proxy par défaut doit être utilisé. Si la propriété Proxy est spécifiée, les paramètres de proxy de la propriété Proxy remplacent l’ordinateur local ou le fichier config 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.*"
. Ainsi, 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 un IPAddress affecté à l’ordinateur local.
- Le suffixe de domaine de la destination correspond au suffixe de domaine de l’ordinateur local (DomainName).
Pour plus d'informations sur la configuration d’un proxy, consultez :