HttpClient

APIs importantes

Utilize HttpClient e a restante API do espaço de nomes Windows.Web.Http para enviar e receber informações utilizando os protocolos HTTP 2.0 e HTTP 1.1.

Tip

As aplicações WinUI 3 destinadas ao .NET 6 ou posterior também podem usar System.Net.Http.HttpClient (o HttpClient do .NET). Suporta IHttpClientFactory, tokens de cancelamento e padrões assíncronos modernos. Use Windows.Web.Http.HttpClient quando precisar de funcionalidades específicas do WinRT, como prompts de credenciais, gestão de cookies através do broker WinRT ou integração com isolamento de rede do Windows. Para pedidos HTTP diretos numa aplicação WinUI 3 .NET, System.Net.Http.HttpClient é frequentemente mais simples.

Descrição geral do HttpClient e do espaço de nomes Windows.Web.Http

As classes no espaço de nomes Windows.Web.Http e nos espaços de nomes relacionados Windows.Web.Http.Headers e Windows.Web.Http.Filters fornecem uma interface de programação para aplicações do Windows que funcionam como cliente HTTP para realizar pedidos GET básicos ou implementar funcionalidades HTTP mais avançadas indicadas abaixo.

  • Métodos para verbos comuns (DELETE, GET, PUT e POST). Cada um destes pedidos é enviado como uma operação assíncrona.

  • Suporte para definições e padrões comuns de autenticação.

  • Acesso aos detalhes de SSL na camada de transporte.

  • Possibilidade de incluir filtros personalizados em aplicações avançadas.

  • Capacidade de obter, definir e eliminar cookies.

  • Informações sobre o progresso do pedido HTTP disponíveis em métodos assíncronos.

A classe Windows.Web.Http.HttpRequestMessage representa uma mensagem de pedido HTTP enviada por Windows.Web.Http.HttpClient. A classe Windows.Web.Http.HttpResponseMessage representa uma mensagem de resposta HTTP recebida na sequência de um pedido HTTP. As mensagens HTTP são definidas no RFC 2616 pelo IETF.

O espaço de nomes Windows.Web.Http representa o conteúdo HTTP como corpo e cabeçalhos da entidade HTTP, incluindo cookies. O conteúdo HTTP pode ser associado a um pedido HTTP ou a uma resposta HTTP. O espaço de nomes Windows.Web.Http fornece várias classes para representar conteúdo HTTP.

O excerto de código na secção "Enviar um pedido GET simples sobre HTTP" utiliza a classe HttpStringContent para representar a resposta HTTP de um pedido HTTP GET como uma string.

O espaço de nomes Windows.Web.Http.Headers suporta a criação de cabeçalhos HTTP e cookies, que são depois associados, como propriedades, aos objetos HttpRequestMessage e HttpResponseMessage.

Enviar um pedido GET simples por HTTP

Como mencionado anteriormente neste artigo, o espaço de nomes Windows.Web.Http permite que aplicações do Windows enviem pedidos GET. O seguinte excerto de código demonstra como enviar um pedido GET para http://www.contoso.com usar o Windows. Web.Http.HttpClient e o Windows. Web.Http.HttpHttpResponseMessage para ler a resposta do pedido 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("http://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"http://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 por HTTP

O exemplo de código C++/WinRT abaixo ilustra o uso de dados de formulário e um pedido POST para enviar uma pequena quantidade de dados binários como carregamento de ficheiro para um servidor web. O código utiliza a classe HttpBufferContent para representar os dados binários, e a classe HttpMultipartFormDataContent para representar os dados do formulário em múltiplas partes.

Observação

Chamar get (como se vê no exemplo de código abaixo) não é apropriado para um tópico de interface. Para a técnica correta a usar nesse caso, veja Concorrência 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 PUBLICAR o conteúdo de um ficheiro binário real (em vez dos dados binários explícitos usados acima), vai achar mais fácil usar um objeto HttpStreamContent . Construa uma instância e, como argumento ao seu construtor, passe o valor devolvido por uma chamada a StorageFile.OpenReadAsync. Esse método devolve um fluxo para os dados dentro do seu ficheiro binário.

Além disso, se estiver a carregar um ficheiro grande (superior a cerca de 10 MB), recomendamos que utilize as APIs de Transferência em Segundo Plano do Windows Runtime.

Enviar dados JSON através de HTTP com POST

O exemplo seguinte publica algum JSON num endpoint e depois escreve 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();
    }
}

Exceções em Windows.Web.Http

É lançada uma exceção quando é transmitida ao construtor do objeto Windows.Foundation.Uri uma cadeia de caracteres inválida para um Identificador Uniforme de Recursos (URI).

.NET: O tipo Windows.Foundation.Uri aparece como System.Uri em C# e VB.

Em C# e Visual Basic, este 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 recebida de um utilizador antes de o URI ser construído.

Em C++, não existe método para tentar analisar uma string para um URI. Se uma aplicação receber dados introduzidos pelo utilizador destinados ao Windows.Foundation.Uri, o construtor deve estar dentro de um bloco try/catch. Se for lançada uma exceção, a aplicação pode notificar o utilizador e solicitar um novo nome de host.

O Windows.Web.Http não tem uma função auxiliar. Assim, uma aplicação que usa HttpClient e outras classes neste namespace precisa de usar o valor HRESULT .

Em aplicações que usam C++/WinRT, a estrutura winrt::hresult_error representa uma exceção levantada durante a execução da aplicação. A função winrt::hresult_error::code devolve o HRESULT atribuído à exceção específica. A função winrt::hresult_error::message devolve a cadeia fornecida pelo sistema associada ao valor HRESULT . Para mais informações, consulte Gestão de erros com C++/WinRT

Os possíveis valores HRESULT estão listados no ficheiro de cabeçalho Winerror.h . A sua aplicação pode filtrar valores específicos do HRESULT para modificar o comportamento da aplicação consoante a causa da exceção.

Em aplicações que utilizam o .NET Framework 4.5 em C#, VB.NET, o System.Exception representa um erro durante a execução da aplicação quando ocorre uma exceção. A propriedade System.Exception.HResult devolve o HRESULT atribuído à exceção específica. A propriedade System.Exception.Message devolve a mensagem que descreve a exceção.

C++/CX foi substituído pelo C++/WinRT. Mas, em aplicações que usam C++/CX, Platform::Exception representa um erro durante a execução da aplicação quando ocorre uma exceção. A propriedade Platform::Exception::HResult devolve o HRESULT atribuído à exceção específica. A propriedade Platform::Exception::Message devolve a cadeia fornecida pelo sistema associada ao valor HRESULT .

Para a maioria dos erros de validação de parâmetros, o HRESULT devolvido é E_INVALIDARG. Para algumas invocações ilegais de métodos, o HRESULT devolvido é E_ILLEGAL_METHOD_CALL.