HttpClient

APIs importantes

Use 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.

Visão geral de HttpClient e o namespace Windows.Web.Http

As classes do namespace Windows.Web.Http e os namespaces Windows.Web.Http.Headers e Windows.Web.Http.Filters relacionados fornecem uma interface de programação para aplicativos UWP (Plataforma Universal do Windows) que atuam como um cliente HTTP para executar solicitações GET básicas ou implementar a funcionalidade HTTP mais avançada listada abaixo.

  • Métodos para verbos comuns (DELETE, GET, PUT e POST). Cada uma dessas solicitações é enviada como uma operação assíncrona.

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

  • Acesso a detalhes do protocolo SSL 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 de uma solicitação HTTP. As mensagens HTTP são definidas na RFC 2616 pela IETF.

O namespace Windows.Web.Http representa conteúdo HTTP como o corpo e os 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.

O trecho 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 GET HTTP como uma cadeia de caracteres.

O namespace Windows.Web.Http.Headers dá suporte à criação de cabeçalhos e cookies HTTP, que são, então, associados como propriedades a objetos HttpRequestMessage e HttpResponseMessage.

Enviar uma solicitação GET simples por HTTP

Conforme mencionado anteriormente neste artigo, o namespace Windows.Web.Http permite que os aplicativos UWP enviem solicitações GET. O snippet de código a seguir demonstra como enviar uma solicitação GET para http://www.contoso.com usando a classe Windows.Web.Http.HttpClient e a classe Windows.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 = "ie";
if (!headers.UserAgent.TryParseAdd(header))
{
    throw new Exception("Invalid header value: " + header);
}

header = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.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"ie" };
    if (!headers.UserAgent().TryParseAdd(header))
    {
        throw L"Invalid header value: " + header;
    }

    header = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.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;
}

Dados binários POST via HTTP

O código de exemplo de C++/WinRT abaixo ilustra o uso de dados de formulário e de 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.

Observação

Chamar get (como visto no exemplo de código abaixo) não é adequado para um thread de interface do usuário. Para a técnica correta a usar 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 lançar 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 de seu arquivo binário.

Além disso, se você está carregando um arquivo grande (maior do que cerca de 10 MB), é recomendável que você use APIs de transferência em segundo plano do Windows Runtime.

Dados JSON de POST por HTTP

O exemplo a seguir posta um JSON para um ponto de extremidade e, em seguida, grava 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

Uma exceção é lançada quando uma cadeia de caracteres inválida para um URI (Uniform Resource Identifier) é passada para o construtor do objeto Windows.Foundation.Uri.

.NET: O tipo Windows.Foundation.Uri é exibido como System.Uri no C# e no VB.

No C# e no 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 de o URI ser 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 lançada, 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 praticidade. Portanto, o 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 returna o HRESULT atribuído à exceção específica. A função winrt::hresult_error::message retorna a cadeia de caracteres fornecida pelo sistema que está associada ao valor HRESULT. Para obter mais informações, confira Tratamento de erro com C++/WinRT

Os valores possíveis de HRESULT estão listados no arquivo de cabeçalho Winerror.h. Seu aplicativo pode filtrar por valores específicos de HRESULT para modificar o comportamento do aplicativo, dependendo da causa da exceção.

Nos aplicativos que usam o .NET Framework 4.5 no 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 nos aplicativos que usam C++/CX, Platform::Exception 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 que está associada ao valor de HRESULT.

Para a maioria dos erros de validação de parâmetro, o HRESULT retornado é E_INVALIDARG. Para algumas chamadas de método ilícitas, o HRESULT retornado é E_ILLEGAL_METHOD_CALL.