HttpClient

重要 API

使用 HttpClient 以及 Windows.Web.Http 命名空間 API 的其餘部分,以透過 HTTP 2.0 和 HTTP 1.1 通訊協定來傳送和接收資訊。

HttpClient 和 Windows.Web.Http 命名空間的概觀

Windows.Web.Http 命名空間中的類別,以及相關 Windows.Web.Http.HeadersWindows.Web.Http.Filters 命名空間中的類別會提供通用 Windows 平台 (UWP) 應用程式的程式設計介面,做為 HTTP 用戶端來執行基本 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,然後兩者會以屬性的形式與 HttpRequestMessageHttpResponseMessage 物件產生關聯。

透過 HTTP 傳送簡單 GET 要求

如本文稍早所述,Windows.Web.Http 命名空間可讓 UWP 應用程式傳送 GET 要求。 下列程式碼片段示範如何使用 Windows.Web.Http.HttpClient 類別將 GET 要求傳送至 http://www.contoso.com,以及使用 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 = "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;
}

透過 HTTP 的 POST 二進位資料

下方 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 的 POST 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 的例外狀況

當統一資源識別元 (URI) 的無效字串傳遞至 Windows.Foundation.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 處理錯誤

可能的 HRESULT 值會列在 Winerror.h 標頭檔中。 您的 app 可以篩選特定 HRESULT 值,依據例外狀況的發生原因來修改 app 行為。

在使用 C#、VB.NET 之 .NET Framework 4.5 的應用程式中,System.Exception 代表例外狀況發生時應用程式執行期間的錯誤。 System.Exception.HResult 屬性會傳回指派給特定例外狀況的 HRESULTSystem.Exception.Message 屬性會傳回描述例外狀況的訊息。

C++/CX 已由 C++/WinRT 取代。 但在使用 C++/CX 的 app 中,Platform::Exception 代表 app 執行期間發生例外狀況時的錯誤。 Platform::Exception::HResult 屬性會傳回指派給特定例外狀況的 HRESULTPlatform::Exception::Message 屬性會傳回與 HRESULT 值相關聯的系統提供字串。

針對大多數的參數驗證錯誤,傳回的 HRESULTE_INVALIDARG。 針對某些不正確的方法呼叫,傳回的 HRESULTE_ILLEGAL_METHOD_CALL