重要 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.標頭和 Windows。Web.Http.Filters 命名空間為 Windows 應用程式提供程式介面,這些應用程式作為 HTTP 用戶端,執行基本的 GET 請求或實作下方列出的更進階 HTTP 功能。
常見動詞的方法(DELETE、GET、PUT 和 POST)。 這些請求都是以非同步操作方式發送。
支援通用的認證設定與模式。
對傳輸層上的安全通訊端層(SSL)詳細資料的存取。
能在進階應用程式中加入自訂篩選功能。
能夠取得、設定及刪除 Cookie。
HTTP 請求進度資訊可透過非同步方法取得。
Windows。Web.Http.HttpRequestMessage 類別代表 Windows 發送的 HTTP 請求訊息。Web.Http.HttpClient。 Windows。Web.Http.HttpResponseMessage 類別代表從 HTTP 請求中接收到的 HTTP 回應訊息。 HTTP 訊息由 IETF 在 RFC 2616 中定義。
Windows。Web.Http 命名空間將 HTTP 內容作為 HTTP 實體主體及標頭(包括 Cookies)來表示。 HTTP 內容可以與 HTTP 請求或 HTTP 回應相關聯。 Windows。Web.Http 命名空間提供多種不同的類別來表示 HTTP 內容。
- HttpBufferContent。 內容作為緩衝區
- HttpFormUrlEncodedContent。 內容為以 application/x-www-form-urlencoded MIME 類型編碼的名稱與值元組
- HttpMultipartContent。 內容以 多部分/* MIME 類型形式呈現。
- HttpMultipartFormDataContent。 內容編碼為 多部分/表單資料 MIME 類型。
- HttpStreamContent。 內容以串流形式(內部類型由 HTTP GET 方法用於接收資料,HTTP POST 方法用於上傳資料)
- HttpStringContent。 內容為字串。
- IHttpContent - 開發者建立自己內容物件的基礎介面
「透過 HTTP 發送簡單 GET 請求」部分的程式碼片段使用 HttpStringContent 類別,將 HTTP GET 請求的 HTTP 回應表示為字串。
Windows。Web.Http.Headers 命名空間支援建立 HTTP 標頭與 Cookie,這些 Cookie 會作為屬性與 HttpRequestMessage 和 HttpResponseMessage 物件關聯。
透過 HTTP 發送一個簡單的 GET 請求
如本文先前提到的,Windows。Web.Http 命名空間允許 Windows 應用程式發送 GET 請求。 以下程式碼片段示範如何使用 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("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;
}
透過 HTTP POST 傳送二進位資料
以下 C++/WinRT 程式碼範例說明利用表單資料與 POST 請求,將少量二進位資料以檔案上傳方式上傳至網頁伺服器。 程式碼使用 HttpBufferContent 類別來表示二進位資料,並使用 HttpMultipartFormDataContent 類別來表示多部分表單資料。
Note
呼叫 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;
}
要發佈實際二進位檔案的內容(而非上述明確的二進位資料),你會發現使用 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 中的例外
當無效的統一資源識別項 (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 函式會回傳指派給特定例外的 HRESULT。 winrt:hresult_error:message 函式會回傳與 HRESULT 值相關聯的系統提供的字串。 更多資訊請參閱 C++/WinRT 的錯誤處理
可能的 HRESULT 值列於 Winerror.h 標頭檔案中。 你的應用程式可以根據異常原因,針對特定的 HRESULT 值進行篩選,修改應用程式行為。
在使用 C#、VB.NET .NET Framework 4.5 的應用程式中,System.Exception 代表應用程式執行中發生異常時的錯誤。 System.Exception.HResult 屬性會回傳指派給該特定例外的 HRESULT。 System.Exception.Message 屬性會回傳描述該例外的訊息。
C++/CX 已被 C++/WinRT 取代。 但在使用 C++/CX 的應用程式中, Platform::Exception 代表應用程式執行時發生異常時的錯誤。 Platform::Exception::HResult 屬性會傳回指派給該特定例外的 HRESULT。 Platform::Exception::Message 屬性會回傳系統提供的字串,該字串與 HRESULT 值相關聯。
對於大多數參數驗證錯誤,回傳的 HRESULT 為 E_INVALIDARG。 對於某些非法方法呼叫,回傳的 HRESULT 是 E_ILLEGAL_METHOD_CALL。