Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
APIs importantes
Use o HttpClient e o restante da API do namespace Windows.Web.Http para enviar e receber informações usando os protocolos HTTP 2.0 e HTTP 1.1.
Tip
Aplicativos WinUI 3 destinados ao .NET 6 ou posterior também podem usar System.Net.Http.HttpClient (o .NET HttpClient). Ele suporta IHttpClientFactory, tokens de cancelamento e padrões assíncronos modernos. Use o Windows.Web.Http.HttpClient quando precisar de recursos específicos do WinRT, como solicitações de credenciais, gerenciamento de cookies por meio do broker do WinRT ou integração com o isolamento de rede do Windows. Para solicitações HTTP simples em um aplicativo WinUI 3 .NET, geralmente é System.Net.Http.HttpClient mais simples.
Visão geral do HttpClient e do namespace Windows.Web.Http
As classes no namespace Windows.Web.Http e nos namespaces relacionados Windows.Web.Http.Headers e Windows.Web.Http.Filters fornecem uma interface de programação para aplicativos do Windows que atuam como clientes HTTP para executar solicitações GET básicas ou implementar funcionalidades HTTP mais avançadas listadas a seguir.
Métodos para verbos comuns (DELETE, GET, PUT e POST). Cada uma dessas solicitações é enviada como uma operação assíncrona.
Suporte para padrões e configurações de autenticação comuns.
Acesso aos detalhes da SSL (Secure Sockets Layer) no transporte.
Capacidade de incluir filtros personalizados em aplicativos avançados.
Capacidade de obter, definir e excluir cookies.
Informações de progresso da solicitação HTTP disponíveis em métodos assíncronos.
A classe Windows.Web.Http.HttpRequestMessage representa uma mensagem de solicitação HTTP enviada por Windows.Web.Http.HttpClient. A classe Windows.Web.Http.HttpResponseMessage representa uma mensagem de resposta HTTP recebida em uma solicitação HTTP. As mensagens HTTP são definidas no RFC 2616 pelo IETF.
O namespace Windows.Web.Http representa o conteúdo HTTP na forma de corpo e cabeçalhos da entidade HTTP, incluindo cookies. O conteúdo HTTP pode ser associado a uma solicitação HTTP ou a uma resposta HTTP. O namespace Windows.Web.Http fornece várias classes diferentes para representar o conteúdo HTTP.
- HttpBufferContent. Conteúdo como buffer
- HttpFormUrlEncodedContent. Conteúdo como tuplas de nome e valor codificadas com o tipo MIME application/x-www-form-urlencoded
- HttpMultipartContent. Conteúdo na forma do tipo MIME multipart/*.
- HttpMultipartFormDataContent. Conteúdo codificado como o tipo MIME multipart/form-data .
- HttpStreamContent. Conteúdo como um fluxo (o tipo interno é usado pelo método HTTP GET para receber dados e o método HTTP POST para carregar dados)
- HttpStringContent. Conteúdo como uma cadeia de caracteres.
- IHttpContent – Uma interface base para os desenvolvedores criarem seus próprios objetos de conteúdo
O snippet de código na seção "Enviar uma solicitação GET simples por HTTP" usa a classe HttpStringContent para representar a resposta HTTP de uma solicitação HTTP GET como uma cadeia de caracteres.
O namespace Windows.Web.Http.Headers dá suporte à criação de cabeçalhos HTTP e cookies, que são então associados como propriedades aos objetos HttpRequestMessage e HttpResponseMessage.
Enviar uma solicitação GET simples por HTTP
Conforme mencionado anteriormente neste artigo, o namespace Windows.Web.Http permite que aplicativos do Windows enviem solicitações GET. O snippet de código a seguir demonstra como enviar uma solicitação GET para http://www.contoso.com usar o Windows. Classe Web.Http.HttpClient e a Windows. Classe Web.Http.HttpResponseMessage para ler a resposta da solicitação 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;
}
Enviar dados binários via HTTP
O exemplo de código C++/WinRT abaixo ilustra o uso de dados de formulário e uma solicitação POST para enviar uma pequena quantidade de dados binários como um upload de arquivo para um servidor Web. O código usa a classe HttpBufferContent para representar os dados binários e a classe HttpMultipartFormDataContent para representar os dados de formulário de várias partes.
Note
Chamar get (como visto no exemplo de código abaixo) não é apropriado para um thread de interface do usuário. Para obter a técnica correta a ser usada nesse caso, consulte Simultaneidade e operações assíncronas com 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;
}
Para POSTAR o conteúdo de um arquivo binário real (em vez dos dados binários explícitos usados acima), você achará mais fácil usar um objeto HttpStreamContent . Construa um e, como o argumento para seu construtor, passe o valor retornado de uma chamada para StorageFile.OpenReadAsync. Esse método retorna um fluxo para os dados dentro do arquivo binário.
Além disso, se você estiver carregando um arquivo grande (maior que cerca de 10 MB), recomendamos que você use as APIs de Transferência em Segundo Plano Windows Runtime.
POSTAR dados JSON por HTTP
O exemplo a seguir envia um JSON para um endpoint e, em seguida, exibe o corpo da resposta.
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();
}
}
Lidar com erros
Uma chamada feita com HttpClient pode falhar de duas maneiras distintas e você lida com cada uma de maneira diferente.
- O servidor responde com um código de status de erro. A solicitação é concluída, mas o servidor retorna um código de status 4xx ou 5xx (por exemplo, 404 Não Encontrado ou 503 Serviço Indisponível). Isso não gera uma exceção. A chamada
GetAsyncouPostAsyncretorna normalmente com uma HttpResponseMessage cuja propriedade IsSuccessStatusCode éfalse. - A solicitação falha antes que uma resposta seja recebida. O cliente não consegue concluir a troca (por exemplo, não há conexão de rede, o nome do host não é resolvido, a conexão expira ou a negociação TLS falha). Isso gera uma exceção.
Como um código de status de erro retornado não lança uma exceção, verificar apenas as exceções não é suficiente. Inspecione a resposta e capture exceções.
Verificar o código de status da resposta
Leia HttpResponseMessage.IsSuccessStatusCode para testar se o servidor retornou um código êxito (2xx). Para ramificar no código específico, leia HttpResponseMessage.StatusCode (um valor HttpStatusCode ) e ReasonPhrase.
Chamar EnsureSuccessStatusCode, como os exemplos anteriores fazem, é um atalho que gera uma exceção quando o código de status não é um código de êxito, para que você possa lidar com ambos os modos de falha em um único catch bloco. Chame-o somente quando você quiser que um código sem êxito seja tratado como um erro. Se você quiser ler o corpo de uma resposta 4xx ou 5xx, consulte IsSuccessStatusCode em vez disso.
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})");
}
Classificar uma exceção de rede
Quando uma solicitação lança uma exceção antes que uma resposta seja recebida (por exemplo, o nome não pode ser resolvido ou a conexão falha ou expira), a propriedade HResult da exceção identifica o erro de rede subjacente. Passe para Windows. Web.WebError.GetStatus para obter um valor WebErrorStatus que descreve a causa (por exemplo, HostNameNotResolved, CannotConnect, Timeoutou ConnectionReset). Use-o para decidir se notificará o usuário, recuará ou tentará novamente.
WebError.GetStatus não se aplica a respostas de erro HTTP (códigos de status 4xx ou 5xx), porque o servidor respondeu. Verifique HttpResponseMessage.IsSuccessStatusCode ou HttpResponseMessage.StatusCode para lidar com eles em vez de chamar 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;
}
}
O mesmo padrão se aplica em C++/WinRT, usando winrt::hresult_error::code como a entrada para 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().
}
}
Tentar novamente após falhas transitórias
O HttpClient não tenta novamente solicitações com falha para você. Para falhas transitórias (os erros de conectividade mostrados acima ou códigos de servidor, como 429 Solicitações em Excesso, 503 Serviço Indisponível e 504 Tempo Limite do Gateway), repita a solicitação por conta própria usando backoff exponencial e respeite o cabeçalho de resposta Retry-After quando o servidor o enviar. Limite o número de tentativas e não tente novamente erros não transitórios, como 400 Solicitação Incorreta ou 404 Não Encontrado.
Exceções em Windows. Web.Http
Uma exceção é gerada quando uma cadeia de caracteres inválida para um URI (Uniform Resource Identifier) é passada para o construtor do Windows. Objeto Foundation.Uri.
.NET: O tipo Windows.Foundation.Uri aparece como System.Uri em C# e VB.
Em C# e Visual Basic, esse erro pode ser evitado usando a classe System.Uri no .NET 4.5 e um dos métodos System.Uri.TryCreate para testar a cadeia de caracteres recebida de um usuário antes que o URI seja construído.
No C++, não há nenhum método para tentar analisar uma cadeia de caracteres para um URI. Se um aplicativo receber entrada do usuário para o Windows.Foundation.Uri, o construtor deverá estar em um bloco try/catch. Se uma exceção for gerada, o aplicativo poderá notificar o usuário e solicitar um novo nome de host.
O Windows. Web.Http não tem uma função de conveniência. Portanto, um aplicativo que usa HttpClient e outras classes nesse namespace precisa usar o valor HRESULT .
Em aplicativos que usam C++/WinRT, o struct winrt::hresult_error representa uma exceção gerada durante a execução do aplicativo. A função winrt::hresult_error::code retorna o HRESULT atribuído à exceção específica. A função winrt::hresult_error::message retorna a cadeia de caracteres fornecida pelo sistema associada ao valor HRESULT . Para obter mais informações, consulte Tratamento de erros com C++/WinRT
Possíveis valores HRESULT são listados no arquivo de cabeçalho Winerror.h . Seu aplicativo pode filtrar valores HRESULT específicos para modificar o comportamento do aplicativo, dependendo da causa da exceção.
Em aplicativos que usam o .NET Framework 4.5 em C#, VB.NET, o System.Exception representa um erro durante a execução do aplicativo quando ocorre uma exceção. A propriedade System.Exception.HResult retorna o HRESULT atribuído à exceção específica. A propriedade System.Exception.Message retorna a mensagem que descreve a exceção.
C++/CX foi substituído por C++/WinRT. Mas em aplicativos que usam C++/CX, a Plataforma::Exceção representa um erro durante a execução do aplicativo quando ocorre uma exceção. A propriedade Platform::Exception::HResult retorna o HRESULT atribuído à exceção específica. A propriedade Platform::Exception::Message retorna a cadeia de caracteres fornecida pelo sistema associada ao valor HRESULT .
Para a maioria dos erros de validação de parâmetro, o HRESULT retornado é E_INVALIDARG. Para algumas chamadas de método ilegais, o HRESULT retornado é E_ILLEGAL_METHOD_CALL.
Tópicos relacionados:
Windows developer