Создание HTTP-запросов с помощью класса HttpClient
В этой статье вы узнаете, как выполнять HTTP-запросы и обрабатывать ответы с HttpClient
помощью класса.
Внимание
Все примеры HTTP-запросов предназначены для одного из следующих URL-адресов:
- https://jsonplaceholder.typicode.com: бесплатный поддельный API для тестирования и прототипирования.
- https://www.example.com: этот домен предназначен для использования в иллюстрирующих примерах в документах.
Конечные точки HTTP обычно возвращают данные нотации объектов JavaScript (JSON), но не всегда. Для удобства необязательный пакет NuGet System.Net.Http.Json предоставляет несколько методов HttpClient
расширения и HttpContent
выполняет автоматическую сериализацию и десериализацию с помощьюSystem.Text.Json
. Примеры, которые следуют за вниманием, относятся к местам, где доступны эти расширения.
Совет
Весь исходный код из этой статьи доступен в репозитории GitHub: Документация .NET.
Создайте HttpClient
.
Большинство из следующих примеров повторно используют один и тот же HttpClient
экземпляр, поэтому необходимо настроить только один раз. Чтобы создать HttpClient
конструктор класса, используйте HttpClient
конструктор класса. Дополнительные сведения см. в руководствах по использованию 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"),
};
Предыдущий код:
- Создает экземпляр нового
HttpClient
экземпляра в качестве переменнойstatic
. В соответствии с рекомендациями рекомендуется повторно использоватьHttpClient
экземпляры во время жизненного цикла приложения. - Задает значение HttpClient.BaseAddress
"https://jsonplaceholder.typicode.com"
.
Этот HttpClient
экземпляр использует базовый адрес при выполнении последующих запросов. Чтобы применить другую конфигурацию, рассмотрим:
- Параметр HttpClient.DefaultRequestHeaders.
- Применение nondefault HttpClient.Timeout.
- Указание HttpClient.DefaultRequestVersion.
Совет
Кроме того, можно создавать HttpClient
экземпляры с помощью подхода к шаблону фабрики, который позволяет настроить любое количество клиентов и использовать их в качестве служб внедрения зависимостей. Дополнительные сведения см. в разделе "Фабрика клиентов HTTP" с помощью .NET.
Создание HTTP-запроса
Чтобы выполнить HTTP-запрос, вызовите любой из следующих API:
Метод 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 |
†A-запрос
USER SPECIFIED
указывает, чтоSendAsync
метод принимает любой допустимыйHttpMethod.
Предупреждение
Выполнение HTTP-запросов считается работой с привязкой к сети ввода-вывода. Хотя существует синхронный метод, рекомендуется использовать асинхронные HttpClient.Send API вместо этого, если у вас нет хорошей причины.
Примечание.
Нацелив устройства Android (например, на разработку .NET MAUI), необходимо добавить android:usesCleartextTraffic="true"
<application></application>
в AndroidManifest.xml. Это позволяет использовать чистый текстовый трафик, например HTTP-запросы, которые в противном случае отключены по умолчанию из-за политик безопасности Android. Рассмотрим следующие примеры параметров XML:
<?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>
Дополнительные сведения см. в разделе Enable clear-text network traffic for the localhost domain.
Содержимое HTTP
Тип HttpContent используется для представления текста сущности HTTP и соответствующих заголовков содержимого. Для методов HTTP (или методов запроса), для которых требуется текст, POST
PUT
и PATCH
, используйте HttpContent класс для указания текста запроса. В большинстве примеров показано, как подготовить StringContent подкласс с полезными данными JSON, но другие подклассы существуют для различных типов содержимого (MIME).
- ByteArrayContent: предоставляет содержимое HTTP на основе массива байтов.
- FormUrlEncodedContent: предоставляет http-содержимое для кортежей имен и значений, закодированных с помощью
"application/x-www-form-urlencoded"
типа MIME. - JsonContent: предоставляет содержимое HTTP на основе JSON.
- MultipartContent: предоставляет коллекцию объектов HttpContent, сериализованных с помощью
"multipart/*"
спецификации типа MIME. - MultipartFormDataContent: предоставляет контейнер для содержимого, закодированного с помощью
"multipart/form-data"
типа MIME. - ReadOnlyMemoryContent: предоставляет содержимое HTTP на ReadOnlyMemory<T>основе .
- StreamContent: предоставляет содержимое HTTP на основе потока.
- StringContent: предоставляет содержимое HTTP на основе строки.
Класс HttpContent
также используется для представления текста отклика HttpResponseMessageсвойства, доступного для HttpResponseMessage.Content свойства.
HTTP Get
Запрос GET
не должен отправлять текст и используется (как указывает имя метода) для получения (или получения) данных из ресурса. Чтобы выполнить HTTP-запрос GET
с учетом HttpClient
URI и URI, используйте 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
// }
}
Предыдущий код:
GET
Выполняет запрос"https://jsonplaceholder.typicode.com/todos/3"
.- Гарантирует успешность ответа.
- Записывает сведения о запросе в консоль.
- Считывает текст ответа в виде строки.
- Записывает текст ответа JSON в консоль.
Это WriteRequestToConsole
пользовательский метод расширения, который не является частью платформы, но если вы хотите узнать, как он реализован, рассмотрите следующий код C#:
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}");
}
}
Эта функция используется для записи сведений о запросе в консоль в следующей форме:
<HTTP Request Method> <Request URI> <HTTP/Version>
Например, GET
запрос на https://jsonplaceholder.typicode.com/todos/3
вывод следующего сообщения:
GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1
HTTP Get from JSON
Конечная https://jsonplaceholder.typicode.com/todos точка возвращает массив JSON объектов todo. Их структура JSON похожа на следующую:
[
{
"userId": 1,
"id": 1,
"title": "example title",
"completed": false
},
{
"userId": 1,
"id": 2,
"title": "another example title",
"completed": true
},
]
Объект C# Todo
определяется следующим образом:
public record class Todo(
int? UserId = null,
int? Id = null,
string? Title = null,
bool? Completed = null);
record class
Это тип, с необязательнымиId
, Completed
Title
и UserId
свойствами. Дополнительные сведения о типе record
см. в разделе "Общие сведения о типах записей в C#". Чтобы автоматически десериализировать запросы в строго типизированный GET
объект C#, используйте GetFromJsonAsync метод расширения, который является частью пакета 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 }
}
В предыдущем коде:
- Запрос
GET
выполняется"https://jsonplaceholder.typicode.com/todos?userId=1&completed=false"
.- Строка запроса представляет критерии фильтрации для запроса.
- Ответ автоматически десериализируется в случае успешного
List<Todo>
выполнения. - Сведения о запросе записываются в консоль вместе с каждым
Todo
объектом.
HTTP Post
Запрос POST
отправляет данные на сервер для обработки. Заголовок Content-Type
запроса означает, какой тип MIME отправляет текст. Чтобы выполнить HTTP-запрос POST
, учитывая HttpClient
и а Uri, используйте 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
// }
}
Предыдущий код:
- Подготавливает StringContent экземпляр с текстом JSON запроса (тип
"application/json"
MIME). POST
Выполняет запрос"https://jsonplaceholder.typicode.com/todos"
.- Гарантирует успешность ответа и запись сведений о запросе в консоль.
- Записывает текст ответа в виде строки в консоль.
HTTP Post в формате JSON
Для автоматической сериализации аргументов запроса и десериализации ответов в строго типизированные POST
объекты C# используйте PostAsJsonAsync метод расширения, который входит в пакет 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 }
}
Предыдущий код:
- Сериализует
Todo
экземпляр в формате JSON и отправляетPOST
запрос"https://jsonplaceholder.typicode.com/todos"
. - Гарантирует успешность ответа и запись сведений о запросе в консоль.
- Десериализирует текст ответа в
Todo
экземпляр и записывает его вTodo
консоль.
HTTP Put
PUT
Метод запроса заменяет существующий ресурс или создает новый с помощью полезных данных текста запроса. Чтобы выполнить HTTP-запрос PUT
с учетом HttpClient
URI и URI, используйте 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
// }
}
Предыдущий код:
- Подготавливает StringContent экземпляр с текстом JSON запроса (тип
"application/json"
MIME). PUT
Выполняет запрос"https://jsonplaceholder.typicode.com/todos/1"
.- Гарантирует успешность ответа и запись сведений о запросе и текст ответа JSON в консоль.
HTTP Put as JSON
Чтобы автоматически сериализовать аргументы запроса и десериализовать ответы в строго типизированные PUT
объекты C#, используйте PutAsJsonAsync метод расширения, который входит в пакет 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 }
}
Предыдущий код:
- Сериализует
Todo
экземпляр в формате JSON и отправляетPUT
запрос"https://jsonplaceholder.typicode.com/todos/5"
. - Гарантирует успешность ответа и запись сведений о запросе в консоль.
- Десериализирует текст ответа в
Todo
экземпляр и записывает его вTodo
консоль.
Исправление HTTP
Запрос PATCH
является частичным обновлением существующего ресурса. Он не создает новый ресурс, и он не предназначен для замены существующего ресурса. Вместо этого он обновляет ресурс только частично. Чтобы выполнить HTTP-запрос PATCH
с учетом HttpClient
URI и URI, используйте 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
// }
}
Предыдущий код:
- Подготавливает StringContent экземпляр с текстом JSON запроса (тип
"application/json"
MIME). PATCH
Выполняет запрос"https://jsonplaceholder.typicode.com/todos/1"
.- Гарантирует успешность ответа и запись сведений о запросе и текст ответа JSON в консоль.
Методы расширения не существуют для PATCH
запросов в пакете System.Net.Http.Json
NuGet.
HTTP Delete
Запрос DELETE
удаляет существующий ресурс. Запрос DELETE
является идемпотентным, но небезопасным, то есть несколько DELETE
запросов к тем же ресурсам дают один и тот же результат, но запрос влияет на состояние ресурса. Чтобы выполнить HTTP-запрос DELETE
с учетом HttpClient
URI и URI, используйте 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
// {}
}
Предыдущий код:
DELETE
Выполняет запрос"https://jsonplaceholder.typicode.com/todos/1"
.- Гарантирует успешность ответа и запись сведений о запросе в консоль.
Совет
Ответ на DELETE
запрос (как PUT
и запрос) может или не включать текст.
Головка HTTP
Запрос HEAD
похож на GET
запрос. Вместо возврата ресурса он возвращает только заголовки, связанные с ресурсом. Ответ на HEAD
запрос не возвращает текст. Чтобы выполнить HTTP-запрос HEAD
, заданный HttpClient
и универсальный код ресурса (URI), используйте HttpClient.SendAsync метод с набором HttpMethod 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
}
Предыдущий код:
HEAD
Выполняет запрос"https://www.example.com/"
.- Гарантирует успешность ответа и запись сведений о запросе в консоль.
- Выполняет итерацию по всем заголовкам ответа, записывая каждую из них в консоль.
Параметры HTTP
Запрос OPTIONS
используется для определения методов HTTP, поддерживаемых сервером или конечной точкой. Чтобы выполнить HTTP-запрос OPTIONS
, заданный HttpClient
и универсальный код ресурса (URI), используйте HttpClient.SendAsync метод с набором HttpMethod 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
}
Предыдущий код:
OPTIONS
Отправляет HTTP-запрос"https://www.example.com/"
в .- Гарантирует успешность ответа и запись сведений о запросе в консоль.
- Выполняет итерацию по всем заголовкам содержимого ответа, записывая каждый из них в консоль.
Трассировка HTTP
Запрос TRACE
может быть полезен для отладки, так как он предоставляет цикл на уровне приложения для сообщения запроса. Чтобы выполнить HTTP-запрос TRACE
, создайте с помощью следующего HttpRequestMessage HttpMethod.Trace
элемента:
using HttpRequestMessage request = new(
HttpMethod.Trace,
"{ValidRequestUri}");
Внимание
Метод TRACE
HTTP не поддерживается всеми HTTP-серверами. Она может предоставлять уязвимость безопасности, если она используется неразумно. Дополнительные сведения см. в разделе Open Web Application Security Project (OWASP): кросс-трассировка сайтов.
Обработка HTTP-ответа
При обработке HTTP-ответа вы взаимодействуете с типом HttpResponseMessage . При оценке допустимости ответа используются несколько членов. Код состояния HTTP доступен через HttpResponseMessage.StatusCode свойство. Представьте, что вы отправили запрос, заданный экземпляром клиента:
using HttpResponseMessage response = await httpClient.SendAsync(request);
Чтобы убедиться, что это response
( OK
код состояния HTTP 200), его можно оценить, как показано в следующем примере:
if (response is { StatusCode: HttpStatusCode.OK })
{
// Omitted for brevity...
}
Существуют другие коды состояния HTTP, представляющие успешный ответ, например CREATED
(код состояния HTTP 201), ACCEPTED
(код состояния HTTP 202), NO CONTENT
(код состояния HTTP 204) и RESET CONTENT
(код состояния HTTP 205). Свойство можно использовать HttpResponseMessage.IsSuccessStatusCode для оценки этих кодов, что гарантирует, что код состояния ответа находится в диапазоне 200–299:
if (response.IsSuccessStatusCode)
{
// Omitted for brevity...
}
Если требуется создать HttpRequestExceptionплатформу, можно вызвать HttpResponseMessage.EnsureSuccessStatusCode() метод:
response.EnsureSuccessStatusCode();
Этот код создает исключение, HttpRequestException
если код состояния ответа не относится к диапазону 200-299.
Ответы на допустимое содержимое HTTP
С допустимым ответом можно получить доступ к тексту ответа с помощью Content свойства. Текст доступен как HttpContent экземпляр, который можно использовать для доступа к тексту в виде потока, массива байтов или строки:
await using Stream responseStream =
await response.Content.ReadAsStreamAsync();
В приведенном выше коде responseStream
можно использовать для чтения текста ответа.
byte[] responseByteArray = await response.Content.ReadAsByteArrayAsync();
В приведенном выше коде responseByteArray
можно использовать для чтения текста ответа.
string responseString = await response.Content.ReadAsStringAsync();
В приведенном выше коде responseString
можно использовать для чтения текста ответа.
Наконец, когда вы знаете, что конечная точка HTTP возвращает JSON, можно десериализировать текст ответа в любой допустимый объект C# с помощью пакета NuGet System.Net.Http.Json :
T? result = await response.Content.ReadFromJsonAsync<T>();
В приведенном выше коде result
текст ответа десериализирован как тип T
.
Обработка ошибок HTTP
При сбое HttpRequestException HTTP-запроса вызывается. Перехват этого исключения может быть недостаточно, так как могут возникнуть другие потенциальные исключения, которые может потребоваться рассмотреть. Например, вызывающий код может использовать маркер отмены, который был отменен до завершения запроса. В этом сценарии вы поймаете следующее 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}");
}
Аналогичным образом, при выполнении HTTP-запроса, если сервер не отвечает до HttpClient.Timeout превышения того же исключения. Однако в этом сценарии можно отличить время ожидания, оценивая Exception.InnerException время ожидания при перехвате 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}");
}
В приведенном выше коде, когда внутреннее исключение является TimeoutException временем ожидания, и запрос не был отменен маркером отмены.
Чтобы оценить код состояния HTTP при перехвате HttpRequestException, можно оценить 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}");
}
В приведенном выше коде метод вызывается для вызова исключения, EnsureSuccessStatusCode() если ответ не выполнен успешно. Затем HttpRequestException.StatusCode свойство вычисляется, чтобы определить, был ли ответ ( 404
код состояния HTTP 404). Существует несколько вспомогательных методов, HttpClient
которые неявно вызывают EnsureSuccessStatusCode
от вашего имени, рассмотрите следующие API:
Совет
Все HttpClient
методы, используемые для выполнения HTTP-запросов, которые не возвращают неявный HttpResponseMessage
вызов EnsureSuccessStatusCode
от вашего имени.
При вызове этих методов можно обработать HttpRequestException
и оценить HttpRequestException.StatusCode свойство, чтобы определить код состояния HTTP ответа:
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}");
}
Могут возникнуть сценарии, в которых необходимо создать в коде HttpRequestException . Конструктор HttpRequestException() является общедоступным, и его можно использовать для создания исключения с пользовательским сообщением:
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}");
}
Прокси-сервер HTTP
Прокси-сервер HTTP можно настроить одним из двух способов. Значение по умолчанию указывается в свойстве HttpClient.DefaultProxy . Кроме того, можно указать прокси-сервер для HttpClientHandler.Proxy свойства.
Глобальный прокси-сервер по умолчанию
Это HttpClient.DefaultProxy
статическое свойство, определяющее прокси-сервер по умолчанию, используемый всеми HttpClient
экземплярами, если прокси-сервер не задан явным образом в переданном конструкторе HttpClientHandler .
Экземпляр по умолчанию, возвращаемый этим свойством, инициализирует следующий набор правил в зависимости от платформы:
- Для Windows: считывает конфигурацию прокси-сервера из переменных среды или, если они не определены, из параметров прокси-сервера пользователя.
- Для macOS: считывает конфигурацию прокси-сервера из переменных среды или, если они не определены, из параметров прокси-сервера системы.
- Для Linux: считывает конфигурацию прокси-сервера из переменных среды или, если они не определены, это свойство инициализирует не настроенный экземпляр, который проходит все адреса.
Переменные среды, используемые для DefaultProxy
инициализации на платформах под управлением Windows и Unix, являются следующими:
HTTP_PROXY
: прокси-сервер, используемый в HTTP-запросах.HTTPS_PROXY
: прокси-сервер, используемый в HTTPS-запросах.ALL_PROXY
: прокси-сервер, используемый в HTTP-запросах и (или) HTTPS в случаеHTTP_PROXY
и /илиHTTPS_PROXY
не определен.NO_PROXY
: список имен узлов, разделенных запятыми, которые следует исключить из прокси-сервера. Звездочки не поддерживаются для подстановочных знаков; используйте ведущую точку в случае, если вы хотите сопоставить поддомен. Примеры:NO_PROXY=.example.com
(с начальной точкой) будет соответствоватьwww.example.com
, но не будет соответствоватьexample.com
.NO_PROXY=example.com
(без ведущих точек) не будет соответствоватьwww.example.com
. Это поведение может быть пересмотрено в будущем, чтобы соответствовать другим экосистемам лучше.
В системах, где для переменных среды учитывается регистр, имена таких переменных могут быть полностью в нижнем или верхнем регистре. Сначала проверяются имена в нижнем регистре.
Прокси-сервер может быть именем узла или IP-адресом, а также двоеточием и номером порта или URL-адресом, http
в том числе именем пользователя и паролем для проверки подлинности прокси-сервера. URL-адрес должен начинаться с http
, а не https
включать текст после имени узла, IP-адреса или порта.
Прокси-сервер на клиент
Свойство HttpClientHandler.Proxy определяет объект, используемый WebProxy для обработки запросов к интернет-ресурсам. Чтобы указать, что прокси-сервер не должен использоваться, задайте Proxy
для свойства экземпляр прокси, возвращаемый методом GlobalProxySelection.GetEmptyWebProxy() .
Локальный компьютер или файл конфигурации приложения может указать, что используется прокси-сервер по умолчанию. Если задано свойство Proxy, то параметры прокси из свойства Прокси переопределяют локальный компьютер или файл конфигурации приложения, а обработчик использует указанные параметры прокси. Если прокси-сервер не указан в файле конфигурации, а свойство Proxy не указано, обработчик использует параметры прокси-сервера, унаследованные от локального компьютера. Если параметры прокси-сервера отсутствуют, запрос отправляется непосредственно серверу.
Класс HttpClientHandler анализирует список обхода прокси-сервера с подстановочными знаками, унаследованными от параметров локального компьютера. Например, HttpClientHandler
класс анализирует список обходов "nt*"
из браузеров как регулярное выражение "nt.*"
. Поэтому URL-адрес http://nt.com
обхода прокси-сервера с помощью HttpClientHandler
класса.
Класс HttpClientHandler
поддерживает обход локального прокси-сервера. Класс считает назначение локальным, если выполняются какие-либо из следующих условий:
- Назначение содержит неструктурированное имя (нет точек в URL-адресе).
- Назначение содержит адрес обратного цикла (Loopback или) или IPv6Loopbackназначение содержит назначенный IPAddress локальному компьютеру адрес.
- Суффикс домена назначения соответствует суффиксу домена локального компьютера (DomainName).
Дополнительные сведения о настройке прокси-сервера см. в следующем разделе: