Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Важные API
Используйте HttpClient и остальную часть Windows. API пространства имен Web.Http для отправки и получения информации с помощью протоколов HTTP 2.0 и HTTP 1.1.
Tip
Приложения WinUI 3, предназначенные для .NET 6 или более поздней версии, также могут использовать System.Net.Http.HttpClient (.NET HttpClient). Он поддерживает IHttpClientFactory, токены отмены и современные асинхронные паттерны. Используйте Windows.Web.Http.HttpClient, если вам нужны специфические для WinRT возможности, такие как запросы на ввод учетных данных, управление файлами cookie через брокер WinRT или интеграция с сетевой изоляцией Windows. Для простых HTTP-запросов в приложении WinUI 3 на .NET элемент System.Net.Http.HttpClient часто оказывается более простым решением.
Обзор HttpClient и пространства имен Windows.Web.Http
Классы в пространстве имен Windows.Web.Http и связанных пространствах имен Windows.Web.Http.Headers и Windows.Web.Http.Filters предоставляют интерфейс программирования для приложений Windows, которые действуют как HTTP-клиент, чтобы выполнять базовые GET-запросы или реализовывать более сложные функции HTTP, перечисленные ниже.
Методы для общих команд (DELETE, GET, PUT и POST). Каждый из этих запросов отправляется как асинхронная операция.
Поддержка распространенных параметров и шаблонов проверки подлинности.
Доступ к сведениям о протоколе SSL для транспорта.
Возможность включать настраиваемые фильтры в расширенные приложения.
Возможность получения, задания и удаления файлов cookie.
Сведения о ходе выполнения HTTP-запроса, доступные в асинхронных методах.
Класс Windows.Web.Http.HttpRequestMessage представляет сообщение HTTP-запроса, отправляемое с помощью Windows.Web.Http.HttpClient. Класс Windows.Web.Http.HttpResponseMessage представляет сообщение HTTP-ответа, полученное в результате HTTP-запроса. HTTP-сообщения определяются в RFC 2616 IETF.
Пространство имен Windows.Web.Http представляет содержимое HTTP в виде тела сущности HTTP и заголовков, включая cookie. Содержимое HTTP может быть связано с HTTP-запросом или HTTP-ответом. Пространство имён Windows.Web.Http предоставляет несколько различных классов для представления HTTP-содержимого.
- HttpBufferContent. Содержимое в качестве буфера
- HttpFormUrlEncodedContent. Содержимое в виде кортежей «имя-значение», закодированное с использованием MIME-типа application/x-www-form-urlencoded
- HttpMultipartContent. Содержимое в форме MIME-типа multipart/*.
- HttpMultipartFormDataContent. Содержимое, закодированное в MIME-типе multipart/form-data.
- HttpStreamContent. Содержимое в виде потока (внутренний тип используется методом HTTP GET для получения данных и метода HTTP POST для отправки данных)
- HttpStringContent. Содержимое в виде строки.
- IHttpContent — базовый интерфейс для разработчиков для создания собственных объектов содержимого
Фрагмент кода в разделе "Отправка простого запроса GET по протоколу HTTP" использует класс HttpStringContent для представления ОТВЕТА HTTP из HTTP-запроса GET в виде строки.
Пространство имён Windows.Web.Http.Headers поддерживает создание заголовков HTTP и файлов cookie, которые затем связаны с объектами HttpRequestMessage и HttpResponseMessage как свойства.
Отправка простого запроса GET по протоколу HTTP
Как уже упоминалось ранее в этой статье, пространство имен Windows.Web.Http позволяет приложениям Windows отправлять запросы GET. В следующем фрагменте кода показано, как отправить GET-запрос к http://www.contoso.com с помощью класса Windows.Web.Http.HttpClient и класса Windows.Web.Http.HttpResponseMessage для чтения ответа на GET-запрос.
//Create an HTTP client object
Windows.Web.Http.HttpClient httpClient = new Windows.Web.Http.HttpClient();
//Add a user-agent header to the GET request.
var headers = httpClient.DefaultRequestHeaders;
//The safe way to add a header value is to use the TryParseAdd method and verify the return value is true,
//especially if the header value is coming from user input.
string header = "MyApp/1.0";
if (!headers.UserAgent.TryParseAdd(header))
{
throw new Exception("Invalid header value: " + header);
}
Uri requestUri = new Uri("https://www.contoso.com");
//Send the GET request asynchronously and retrieve the response as a string.
Windows.Web.Http.HttpResponseMessage httpResponse = new Windows.Web.Http.HttpResponseMessage();
string httpResponseBody = "";
try
{
//Send the GET request
httpResponse = await httpClient.GetAsync(requestUri);
httpResponse.EnsureSuccessStatusCode();
httpResponseBody = await httpResponse.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
httpResponseBody = "Error: " + ex.HResult.ToString("X") + " Message: " + ex.Message;
}
// pch.h
#pragma once
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.Http.Headers.h>
// main.cpp : Defines the entry point for the console application.
#include "pch.h"
#include <iostream>
using namespace winrt;
using namespace Windows::Foundation;
int main()
{
init_apartment();
// Create an HttpClient object.
Windows::Web::Http::HttpClient httpClient;
// Add a user-agent header to the GET request.
auto headers{ httpClient.DefaultRequestHeaders() };
// The safe way to add a header value is to use the TryParseAdd method, and verify the return value is true.
// This is especially important if the header value is coming from user input.
std::wstring header{ L"MyApp/1.0" };
if (!headers.UserAgent().TryParseAdd(header))
{
throw L"Invalid header value: " + header;
}
Uri requestUri{ L"https://www.contoso.com" };
// Send the GET request asynchronously, and retrieve the response as a string.
Windows::Web::Http::HttpResponseMessage httpResponseMessage;
std::wstring httpResponseBody;
try
{
// Send the GET request.
httpResponseMessage = httpClient.GetAsync(requestUri).get();
httpResponseMessage.EnsureSuccessStatusCode();
httpResponseBody = httpResponseMessage.Content().ReadAsStringAsync().get();
}
catch (winrt::hresult_error const& ex)
{
httpResponseBody = ex.message();
}
std::wcout << httpResponseBody;
}
Отправка двоичных данных методом POST по протоколу HTTP
Приведенный ниже пример кода C++/WinRT иллюстрирует использование данных формы и запроса POST для отправки небольшого объема двоичных данных в виде файла на веб-сервер. Код использует класс HttpBufferContent для представления двоичных данных и класса HttpMultipartFormDataContent для представления данных формы с несколькими частями.
Note
Вызов get (как показано в приведенном ниже примере кода) не подходит для потока пользовательского интерфейса. Правильный метод, используемый в этом случае, см. в разделе параллелизм и асинхронные операции с C++/WinRT.
// pch.h
#pragma once
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Security.Cryptography.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Web.Http.Headers.h>
// main.cpp : Defines the entry point for the console application.
#include "pch.h"
#include <iostream>
#include <sstream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
int main()
{
init_apartment();
auto buffer{
Windows::Security::Cryptography::CryptographicBuffer::ConvertStringToBinary(
L"A sentence of text to encode into binary to serve as sample data.",
Windows::Security::Cryptography::BinaryStringEncoding::Utf8
)
};
Windows::Web::Http::HttpBufferContent binaryContent{ buffer };
// You can use the 'image/jpeg' content type to represent any binary data;
// it's not necessarily an image file.
binaryContent.Headers().Append(L"Content-Type", L"image/jpeg");
Windows::Web::Http::Headers::HttpContentDispositionHeaderValue disposition{ L"form-data" };
binaryContent.Headers().ContentDisposition(disposition);
// The 'name' directive contains the name of the form field representing the data.
disposition.Name(L"fileForUpload");
// Here, the 'filename' directive is used to indicate to the server a file name
// to use to save the uploaded data.
disposition.FileName(L"file.dat");
Windows::Web::Http::HttpMultipartFormDataContent postContent;
postContent.Add(binaryContent); // Add the binary data content as a part of the form data content.
// Send the POST request asynchronously, and retrieve the response as a string.
Windows::Web::Http::HttpResponseMessage httpResponseMessage;
std::wstring httpResponseBody;
try
{
// Send the POST request.
Uri requestUri{ L"https://www.contoso.com/post" };
Windows::Web::Http::HttpClient httpClient;
httpResponseMessage = httpClient.PostAsync(requestUri, postContent).get();
httpResponseMessage.EnsureSuccessStatusCode();
httpResponseBody = httpResponseMessage.Content().ReadAsStringAsync().get();
}
catch (winrt::hresult_error const& ex)
{
httpResponseBody = ex.message();
}
std::wcout << httpResponseBody;
}
Для POST содержимого фактического двоичного файла (а не явных двоичных данных, используемых выше), проще использовать объект HttpStreamContent . Создайте одну и в качестве аргумента в конструктор передайте значение, возвращаемое из вызова StorageFile.OpenReadAsync. Этот метод возвращает поток данных в двоичном файле.
Кроме того, если вы загружаете большой файл (размером более 10 МБ), мы рекомендуем использовать API Background Transfer среды выполнения Windows.
Отправка данных JSON по HTTP методом POST
В следующем примере в конечную точку записывается часть JSON, а затем записывается текст ответа.
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Web.Http;
private async Task TryPostJsonAsync()
{
try
{
// Construct the HttpClient and Uri. This endpoint is for test purposes only.
HttpClient httpClient = new HttpClient();
Uri uri = new Uri("https://www.contoso.com/post");
// Construct the JSON to post.
HttpStringContent content = new HttpStringContent(
"{ \"firstName\": \"Eliot\" }",
UnicodeEncoding.Utf8,
"application/json");
// Post the JSON and wait for a response.
HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(
uri,
content);
// Make sure the post succeeded, and write out the response.
httpResponseMessage.EnsureSuccessStatusCode();
var httpResponseBody = await httpResponseMessage.Content.ReadAsStringAsync();
Debug.WriteLine(httpResponseBody);
}
catch (Exception ex)
{
// Write out any exceptions.
Debug.WriteLine(ex);
}
}
// pch.h
#pragma once
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Security.Cryptography.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Web.Http.Headers.h>
// main.cpp : Defines the entry point for the console application.
#include "pch.h"
#include <iostream>
#include <sstream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
int main()
{
init_apartment();
Windows::Web::Http::HttpResponseMessage httpResponseMessage;
std::wstring httpResponseBody;
try
{
// Construct the HttpClient and Uri. This endpoint is for test purposes only.
Windows::Web::Http::HttpClient httpClient;
Uri requestUri{ L"https://www.contoso.com/post" };
// Construct the JSON to post.
Windows::Web::Http::HttpStringContent jsonContent(
L"{ \"firstName\": \"Eliot\" }",
UnicodeEncoding::Utf8,
L"application/json");
// Post the JSON, and wait for a response.
httpResponseMessage = httpClient.PostAsync(
requestUri,
jsonContent).get();
// Make sure the post succeeded, and write out the response.
httpResponseMessage.EnsureSuccessStatusCode();
httpResponseBody = httpResponseMessage.Content().ReadAsStringAsync().get();
std::wcout << httpResponseBody.c_str();
}
catch (winrt::hresult_error const& ex)
{
std::wcout << ex.message().c_str();
}
}
Управление ошибками
Вызов, сделанный с использованием HttpClient, может завершиться сбоем по двум разным сценариям, и каждый из них требует своего подхода к обработке.
- Сервер отвечает с кодом состояния ошибки. Запрос завершается, но сервер возвращает код состояния 4xx или 5xx (например, 404 Not Found или 503 Service Not Foundable). Это не вызывает исключение. Вызов
GetAsyncили обычно возвращает объектfalse, у которого свойство IsSuccessStatusCode равноPostAsync. - Запрос завершается ошибкой до получения ответа. Клиент вообще не может завершить обмен (например, нет сетевого подключения, не удаётся разрешить имя хоста, истекает время ожидания подключения или не удаётся согласовать TLS). В этом случае создается исключение.
Так как возвращенный код состояния ошибки не вызывается, проверка только для исключений недостаточно. Проверьте ответ и перехватывайте исключения.
Проверка кода состояния ответа
Прочитайте HttpResponseMessage.IsSuccessStatusCode , чтобы проверить, возвращает ли сервер код успешного выполнения (2xx). Чтобы выполнить ветвление в зависимости от конкретного кода, прочитайте HttpResponseMessage.StatusCode (значение HttpStatusCode) и ReasonPhrase.
Вызов EnsureSuccessStatusCode, как и в предыдущих примерах, — это ярлык, который создает исключение, если код состояния не является кодом успешного выполнения, поэтому вы можете обрабатывать оба режима сбоя в одном catch блоке. Вызовите его только в том случае, если требуется, чтобы код, отличный от успешного выполнения, рассматривался как ошибка. Если вы хотите прочитать тело 4xx- или 5xx-ответа, вместо этого проверьте IsSuccessStatusCode.
Windows.Web.Http.HttpClient httpClient = new Windows.Web.Http.HttpClient();
Uri requestUri = new Uri("https://www.contoso.com");
Windows.Web.Http.HttpResponseMessage response = await httpClient.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
string body = await response.Content.ReadAsStringAsync();
// Process the successful response.
}
else
{
// The server responded, but with an error status code.
System.Diagnostics.Debug.WriteLine($"Request failed: {(int)response.StatusCode} {response.StatusCode} ({response.ReasonPhrase})");
}
Классификация сетевого исключения
Когда запрос вызывается до получения ответа (например, имя не может быть разрешено, или подключение завершается сбоем или истекает время ожидания), исключение HResult определяет базовую сетевую ошибку. Передайте его в метод Windows.Web.WebError.GetStatus, чтобы получить значение WebErrorStatus, описывающее причину (например, HostNameNotResolved, CannotConnect, Timeout или ConnectionReset). Используйте это, чтобы определить, нужно ли уведомить пользователя, использовать запасной вариант или повторить попытку.
WebError.GetStatus не применяется к ответам об ошибках HTTP (коды состояния 4xx или 5xx), так как сервер ответил. Проверьте httpResponseMessage.IsSuccessStatusCode или HttpResponseMessage.StatusCode , чтобы обрабатывать их вместо вызова EnsureSuccessStatusCode.
Windows.Web.Http.HttpClient httpClient = new Windows.Web.Http.HttpClient();
Uri requestUri = new Uri("https://www.contoso.com");
try
{
Windows.Web.Http.HttpResponseMessage response = await httpClient.GetAsync(requestUri);
if (!response.IsSuccessStatusCode)
{
// Handle the non-success HTTP status code (for example, 404 Not Found or 503 Service Unavailable).
System.Diagnostics.Debug.WriteLine($"HTTP error: {(int)response.StatusCode} {response.StatusCode}");
return;
}
string body = await response.Content.ReadAsStringAsync();
// Process the successful response.
}
catch (Exception ex)
{
Windows.Web.WebErrorStatus status = Windows.Web.WebError.GetStatus(ex.HResult);
switch (status)
{
case Windows.Web.WebErrorStatus.HostNameNotResolved:
case Windows.Web.WebErrorStatus.CannotConnect:
case Windows.Web.WebErrorStatus.Timeout:
case Windows.Web.WebErrorStatus.ConnectionReset:
// A transient connectivity problem. Retrying with backoff may succeed.
System.Diagnostics.Debug.WriteLine($"Network error: {status}.");
break;
case Windows.Web.WebErrorStatus.Unknown:
// GetStatus couldn't map the HRESULT to a WebErrorStatus value.
System.Diagnostics.Debug.WriteLine($"Unmapped error. HRESULT: 0x{ex.HResult:X8} {ex.Message}");
break;
default:
System.Diagnostics.Debug.WriteLine($"Web error: {status}");
break;
}
}
Тот же шаблон применяется в C++/WinRT, используя winrt::hresult_error::code в качестве входных данных GetStatus.
// #include <winrt/Windows.Web.h>
try
{
auto response{ httpClient.GetAsync(requestUri).get() };
if (!response.IsSuccessStatusCode())
{
// Handle the non-success HTTP status code (for example, 404 Not Found or 503 Service Unavailable).
}
else
{
auto body{ response.Content().ReadAsStringAsync().get() };
// Process the successful response.
}
}
catch (winrt::hresult_error const& ex)
{
Windows::Web::WebErrorStatus status{ Windows::Web::WebError::GetStatus(ex.code()) };
if (status == Windows::Web::WebErrorStatus::HostNameNotResolved ||
status == Windows::Web::WebErrorStatus::CannotConnect ||
status == Windows::Web::WebErrorStatus::Timeout ||
status == Windows::Web::WebErrorStatus::ConnectionReset)
{
// A transient connectivity problem. Retrying with backoff may succeed.
}
else
{
// Inspect status, or fall back to ex.code() and ex.message().
}
}
Повторить при временных сбоях
HttpClient не повторяет неудачные запросы. При временных сбоях (ошибках подключения, указанных выше, или кодах состояния сервера, таких как 429 Too Many Requests, 503 Service Unavailable и 504 Gateway Timeout) повторите запрос самостоятельно, используя экспоненциальную задержку между повторами, и учитывайте заголовок ответа Retry-After, когда сервер его отправляет. Ограничьте число попыток и не выполняйте повторные попытки при ошибках, не являющихся временными, таких как 400 Неверный запрос или 404 Не найдено.
Исключения в Windows. Web.Http
Исключение возникает, если в конструктор объекта Windows.Foundation.Uri передается недопустимая строка универсального идентификатора ресурса (URI).
.NET: Тип Windows.Foundation.Uri отображается как System.Uri в C# и VB.
В C# и Visual Basic эту ошибку можно избежать с помощью класса System.Uri в .NET 4.5 и одного из методов System.Uri.TryCreate для проверки строки, полученной пользователем до создания URI.
В C++не существует метода для анализа строки в URI. Если приложение получает входные данные от пользователя для Windows. Foundation.Uri конструктор должен находиться в блоке try/catch. Если возникает исключение, приложение может уведомить пользователя и запросить новое имя узла.
Windows. Web.Http не имеет удобной функции. Поэтому приложению, использующему HttpClient и другие классы в этом пространстве имен, необходимо использовать значение HRESULT.
В приложениях с помощью C++/WinRT структура winrt::hresult_error представляет исключение, возникщее во время выполнения приложения. Функция winrt::hresult_error::code возвращает HRESULT, связанный с конкретным исключением. Функция winrt::hresult_error::message возвращает системную строку, связанную со значением HRESULT . Дополнительные сведения см. в разделе об обработке ошибок с помощью C++/WinRT
Возможные значения HRESULT перечислены в файле заголовка Winerror.h . Приложение может фильтровать определенные значения HRESULT , чтобы изменить поведение приложения в зависимости от причины исключения.
В приложениях, использующих .NET Framework 4.5 в C#, VB.NET, system.Exception представляет ошибку во время выполнения приложения при возникновении исключения. Свойство System.Exception.HResult возвращает HRESULT , назначенное конкретному исключению. Свойство System.Exception.Message возвращает сообщение, описывающее исключение.
C++/CX заменен C++/WinRT. Но в приложениях, использующих C++/CX, платформа::Exception представляет ошибку во время выполнения приложения при возникновении исключения. Свойство Platform::Exception::HResult возвращает HRESULT, присвоенный конкретному исключению. Свойство Platform::Exception::Message возвращает указанную системой строку, связанную со значением HRESULT .
Для большинства ошибок проверки параметров возвращаемое значение HRESULT — E_INVALIDARG. При некоторых недопустимых вызовах методов возвращаемое значение HRESULT равно E_ILLEGAL_METHOD_CALL.
Связанные темы
Windows developer