HttpClient

重要的 API

使用 HttpClient 以及 Windows.Web.Http 命名空间 API 的其余部分,通过 HTTP 2.0 和 HTTP 1.1 协议发送和接收信息。

Tip

面向 .NET 6 或更高版本的 WinUI 3 应用也可以使用 System.Net.Http.HttpClient (.NET HttpClient)。 它支持 IHttpClientFactory、取消令牌和新式异步模式。 如果需要 WinRT 特有的功能,例如凭据提示、通过 WinRT 代理进行 Cookie 管理,或与 Windows 网络隔离集成,请使用 Windows.Web.Http.HttpClient。 对于 .NET WinUI 3 应用中的直接 HTTP 请求,System.Net.Http.HttpClient通常更简单。

HttpClient 和 Windows.Web.Http 命名空间概述

Windows中的类。Web.Http 命名空间和相关Windows。Web.Http.HeadersWindows。Web.Http.Filters 命名空间为充当 HTTP 客户端的Windows应用提供编程接口,以执行基本 GET 请求或实现下面列出的更高级的 HTTP 功能。

  • 常见谓词的方法(DELETEGETPUTPOST)。 其中每个请求都作为异步操作发送。

  • 支持常见的身份验证设置和模式。

  • 访问有关传输的安全套接字层(SSL)的详细信息。

  • 能够在高级应用中包括自定义筛选器。

  • 能够获取、设置和删除 Cookie。

  • 异步方法上提供的 HTTP 请求进度信息。

Windows.Web.Http.HttpRequestMessage 类表示由 Windows.Web.Http.HttpClient 发送的 HTTP 请求消息。 Windows。Web.Http.HttpResponseMessage 类表示从 HTTP 请求收到的 HTTP 响应消息。 HTTP 消息由 IETF 在 RFC 2616 中定义。

Windows。Web.Http 命名空间将 HTTP 内容表示为 HTTP 实体正文和标头,包括 Cookie。 HTTP 内容可与 HTTP 请求或 HTTP 响应相关联。 Windows。Web.Http 命名空间提供许多不同的类来表示 HTTP 内容。

“通过 HTTP 发送简单的 GET 请求”部分中的代码片段使用 HttpStringContent 类将来自 HTTP GET 请求的 HTTP 响应表示为字符串。

Windows。Web.Http.Headers 命名空间支持创建 HTTP 标头和 Cookie,这些标头和 Cookie 随后作为属性与 HttpRequestMessageHttpResponseMessage 对象相关联。

通过 HTTP 发送简单的 GET 请求

如本文前面所述,Windows。Web.Http 命名空间允许Windows应用发送 GET 请求。 以下代码片段演示如何使用Windows.Web.Http.HttpClient 类向http://www.contoso.com发送 GET 请求,并使用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("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;
}

通过 HTTP 发布二进制数据

下面的 C++/WinRT 代码示例演示了如何使用表单数据和 POST 请求将少量二进制数据作为文件上传到 Web 服务器。 代码使用 HttpBufferContent 类来表示二进制数据,使用 HttpMultipartFormDataContent 类表示多部分表单数据。

注释

调用 get (如下面的代码示例所示)不适用于 UI 线程。 有关在这种情况下使用的正确技术,请参阅 使用 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 返回的值作为其构造函数的参数传入。 该方法返回二进制文件中数据的流。

此外,如果要上传大型文件(大于 10MB),则建议使用Windows 运行时后台传输 API。

通过 HTTP 发布 JSON 数据

以下示例将一些 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();
    }
}

Windows.Web.Http 中的异常

当向 Windows.Foundation.Uri 对象的构造函数传递无效的统一资源标识符 (URI) 字符串时,会引发异常。

.NET:Windows。Foundation.Uri 类型在 C# 和 VB 中显示为 System.Uri

在 C# 和 Visual Basic 中,可以使用 .NET 4.5 中的 System.Uri 类和 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 函数返回分配给特定异常的 HRESULTwinrt::hresult_error::message 函数返回与 HRESULT 值关联的系统提供的字符串。 有关详细信息,请参阅 C++/WinRT 的错误处理

Winerror.h 头文件中列出了可能的 HRESULT 值。 应用可以根据异常的原因筛选特定的 HRESULT 值以修改应用行为。

在 C#、VB.NET 中使用 .NET Framework 4.5 的应用中,当发生异常时,System.Exception 表示应用执行期间出错。 System.Exception.HResult 属性返回分配给特定异常的 HRESULTSystem.Exception.Message 属性返回描述异常的消息。

C++/CX 已被 C++/WinRT 取代。 但在使用 C++/CX 的应用中, Platform::Exception 表示在发生异常时应用执行期间出错。 Platform::Exception::HResult 属性返回分配给特定异常的 HRESULTPlatform::Exception::Message 属性返回与 HRESULT 值关联的系统提供的字符串。

对于大多数参数验证错误,返回的 HRESULTE_INVALIDARG。 对于某些非法的方法调用,返回的 HRESULTE_ILLEGAL_METHOD_CALL