HttpClient

důležitá rozhraní API

Použijte HttpClient a ostatní rozhraní API v oboru názvů Windows.Web.Http k odesílání a přijímání informací pomocí protokolů HTTP 2.0 a HTTP 1.1.

Tip

Aplikace WinUI 3, které cílí na .NET 6 nebo novější, můžou také používat System.Net.Http.HttpClient (.NET HttpClient). Podporuje IHttpClientFactory, tokeny zrušení a moderní asynchronní vzory. Použijte Windows.Web.Http.HttpClient, když potřebujete funkce specifické pro technologii WinRT, jako jsou výzvy k zadání přihlašovacích údajů, správa souborů cookie prostřednictvím zprostředkovatele WinRT nebo integrace s izolací sítě systému Windows. V aplikaci .NET WinUI 3 je pro jednoduché požadavky HTTP často jednodušší System.Net.Http.HttpClient.

Přehled HttpClient a oboru názvů Windows.Web.Http

Třídy v oboru názvů Windows.Web.Http a v souvisejících oborech názvů Windows.Web.Http.Headers a Windows.Web.Http.Filters poskytují programové rozhraní pro aplikace pro Windows, které fungují jako klient HTTP, k provádění základních požadavků GET nebo k implementaci pokročilejších funkcí HTTP uvedených níže.

  • Metody pro běžné příkazy (DELETE, GET, PUT a POST). Každý z těchto požadavků se odešle jako asynchronní operace.

  • Podpora běžných nastavení a vzorů ověřování

  • Přístup k podrobnostem protokolu SSL (Secure Sockets Layer) o přenosu

  • Možnost zahrnout přizpůsobené filtry do pokročilých aplikací

  • Možnost získat, nastavit a odstranit soubory cookie.

  • Informace o průběhu požadavku HTTP dostupné u asynchronních metod.

Třída Windows.Web.Http.HttpRequestMessage představuje zprávu požadavku HTTP odeslanou třídou Windows.Web.Http.HttpClient. Třída Windows.Web.Http.HttpResponseMessage představuje zprávu HTTP odpovědi přijatou na základě požadavku HTTP. Zprávy HTTP jsou definovány v RFC 2616 pomocí IETF.

Obor názvů Windows.Web.Http představuje obsah protokolu HTTP jako tělo a hlavičky entity HTTP, včetně souborů cookie. Obsah HTTP může být přidružený k požadavku HTTP nebo odpovědi HTTP. Obor názvů Windows.Web.Http poskytuje řadu různých tříd, které slouží k reprezentaci obsahu HTTP.

Fragment kódu v části "Send a simple GET request over HTTP" (Odeslat jednoduchý požadavek GET přes HTTP) používá třídu HttpStringContent k reprezentaci odpovědi HTTP z požadavku HTTP GET jako řetězce.

Obor názvů Windows.Web.Http.Headers podporuje vytváření hlaviček HTTP a souborů cookie, které jsou pak přidruženy jako vlastnosti k objektům HttpRequestMessage a HttpResponseMessage.

Odeslání jednoduchého požadavku GET přes HTTP

Jak již bylo v tomto článku zmíněno, obor názvů Windows.Web.Http umožňuje aplikacím pro Windows odesílat požadavky GET. Následující fragment kódu ukazuje, jak odeslat požadavek GET na http://www.contoso.com pomocí třídy Windows.Web.Http.HttpClient a třídy Windows.Web.Http.HttpResponseMessage pro čtení odpovědi na požadavek 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;
}

Odeslat binární data přes HTTP

Následující příklad kódu C++/WinRT znázorňuje použití dat formuláře a požadavku POST k odeslání malého množství binárních dat jako souboru nahrání na webový server. Kód používá třídu HttpBufferContent k reprezentaci binárních dat a třídu HttpMultipartFormDataContent k reprezentaci vícedílných dat formuláře.

Note

Volání get (viz níže uvedený příklad kódu) není vhodné pro vlákno uživatelského rozhraní. Správnou techniku použití v takovém případě najdete v tématu Souběžnost a asynchronní operace s 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;
}

Pokud chcete postovat obsah skutečného binárního souboru (místo explicitních binárních dat použitých výše), zjistíte, že je jednodušší použít HttpStreamContent objektu. Vytvořte jeden a jako argument konstruktoru předejte hodnotu vrácenou z volání StorageFile.OpenReadAsync. Tato metoda vrátí datový tok s daty uvnitř vašeho binárního souboru.

Pokud nahráváte velký soubor (větší než asi 10 MB), doporučujeme použít rozhraní API pro přenos na pozadí prostředí Windows Runtime.

Odesílat data JSON přes protokol HTTP metodou POST

Následující příklad publikuje kód JSON do koncového bodu a pak zapíše text odpovědi.

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();
    }
}

Řešte chyby

Volání provedené pomocí HttpClient může selhat dvěma různými způsoby a každý z nich zpracujete jinak.

  • Server odpoví stavovým kódem chyby. Požadavek se dokončí, ale server vrátí stavový kód 4xx nebo 5xx (například 404 Nenalezena nebo 503 Služba není k dispozici). Toto nevyvolá výjimku. Volání GetAsync nebo PostAsync se normálně vrátí s objektem HttpResponseMessage, jehož vlastnost IsSuccessStatusCode má hodnotu false.
  • Požadavek se nezdaří před přijetím odpovědi. Klient vůbec nemůže dokončit komunikaci (například není k dispozici síťové připojení, název hostitele nelze přeložit, dojde k vypršení časového limitu připojení nebo selže vyjednávání protokolu TLS). Tím dojde k výjimce.

Vzhledem k tomu, že vrácený stavový kód chyby nevyvolá, kontrola pouze výjimek nestačí. Zkontrolujte odpověď a zachyťte výjimky.

Kontrola stavového kódu odpovědi

Přečtěte si HttpResponseMessage.IsSuccessStatusCode a otestujte, jestli server vrátil kód úspěchu (2xx). Chcete-li rozlišovat podle konkrétního kódu, přečtěte hodnoty HttpResponseMessage.StatusCode (hodnotu HttpStatusCode) a ReasonPhrase.

Volání EnsureSuccessStatusCode, jak to dělají předchozí příklady, představuje zkratku, která vyvolá výjimku, pokud stavový kód neoznačuje úspěch, takže můžete zpracovat oba typy selhání v jednom catch bloku. Volejte ho jenom v případě, že chcete, aby se kód bez úspěchu považoval za chybu. Pokud si chcete přečíst tělo odpovědi u odpovědi 4xx nebo 5xx, podívejte se místo toho na 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})");
}

Klasifikace výjimky sítě

Když se požadavek vyvolá před přijetím odpovědi (například název se nedá vyřešit nebo dojde k selhání nebo vypršení časového limitu připojení), identifikuje výjimka HResult základní chybu sítě. Předejte ho Windows. Web.WebError.GetStatus k získání hodnoty WebErrorStatus, která popisuje příčinu (například HostNameNotResolved, CannotConnect, Timeoutnebo ConnectionReset). Použijte ho k rozhodnutí, jestli chcete uživatele upozornit, vrátit se zpět nebo zkusit to znovu.

WebError.GetStatus se nevztahuje na chybové odpovědi HTTP (stavové kódy 4xx nebo 5xx), protože server odpověděl. Zkontrolujte HttpResponseMessage.IsSuccessStatusCode nebo HttpResponseMessage.StatusCode a zpracujte je namísto volání 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;
    }
}

Stejný vzor platí v jazyce C++/WinRT pomocí winrt::hresult_error::code jako vstup pro 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().
    }
}

Opakování přechodných selhání

HttpClient za vás nezopakuje neúspěšné požadavky. V případě přechodných selhání (výše uvedených chyb konektivity nebo kódů serveru, jako jsou 429 Too Many Requests, 503 Service Unavailable a 504 Gateway Timeout) opakujte požadavek s exponenciálně se prodlužující prodlevou a respektujte hlavičku odpovědi Retry-After, pokud ji server odešle. Zakažte počet pokusů a neopakujte přechodné chyby, jako je například 400 Chybný požadavek nebo 404 Nenalezena.

Výjimky v Windows Web.Http

Výjimka je vyvolána, když je konstruktoru objektu Windows.Foundation.Uri předán neplatný řetězec pro identifikátor URI (Uniform Resource Identifier).

.NET: Typ Windows.Foundation.Uri se v jazycích C# a VB zobrazuje jako System.Uri.

V jazyce C# a Visual Basic se této chybě můžete vyhnout použitím třídy System.Uri v .NET 4.5 a jedné z metod System.Uri.TryCreate k otestování řetězce přijatého od uživatele před vytvořením identifikátoru URI.

V jazyce C++ neexistuje žádná metoda, která by se pokusila analyzovat řetězec na identifikátor URI. Pokud aplikace získá vstup od uživatele pro Windows. Foundation.Uri, konstruktor by měl být v bloku try/catch. Pokud dojde k výjimce, aplikace může uživatele upozornit a požádat o nový název hostitele.

Windows.Web.Http postrádá pomocnou funkci. Aplikace využívající HttpClient a další třídy v tomto oboru názvů proto musí používat hodnotu HRESULT .

V aplikacích používajících C++/WinRT představuje struktura winrt::hresult_error výjimku vyvolanou při provádění aplikace. Funkce winrt::hresult_error::code vrátí hodnotu HRESULT přiřazenou ke konkrétní výjimce. Funkce winrt::hresult_error:message vrátí systémový řetězec přidružený k hodnotě HRESULT . Další informace najdete v tématu Zpracování chyb pomocí C++/WinRT.

Možné hodnoty HRESULT jsou uvedeny v souboru hlaviček Winerror.h . Aplikace může filtrovat konkrétní hodnoty HRESULT a měnit chování aplikace v závislosti na příčině výjimky.

V aplikacích používajících .NET Framework 4.5 v jazyce C#, VB.NET představuje System.Exception chybu při provádění aplikace, když dojde k výjimce. System.Exception.HResult vlastnost vrátí HRESULT přiřazené ke konkrétní výjimce. Vlastnost System.Exception.Message vrátí zprávu, která popisuje výjimku.

C++/CX nahradil C++/WinRT. V aplikacích používajících C++/CX ale platform::Exception představuje chybu při provádění aplikace, když dojde k výjimce. Vlastnost Platform::Exception::HResult vrátí hodnotu HRESULT přiřazenou ke konkrétní výjimce. Vlastnost Platform::Exception::Message vrátí systémový řetězec přidružený k hodnotě HRESULT .

U většiny chyb ověřování parametrů je vrácena hodnota HRESULTE_INVALIDARG. U některých nepovolených volání metod je vrácená hodnota HRESULTE_ILLEGAL_METHOD_CALL.