標籤:
14.2 網路編程之HttpClient類
除了可以使用HttpWebRequest類來實現HTTP網路請求之外,還可以使用HttpClient類來實現。對於基本的請求操作,HttpClient類提供了一個簡單的介面來處理最常見的任務,並為身分識別驗證提供了適用於大多數方案的合理的預設設定。對於較為複雜的 HTTP 操作,更多的功能包括:執行常見操作(DELETE、GET、PUT 和 POST)的方法;擷取、設定和刪除 Cookie 的功能;支援常見的身分識別驗證設定和模式;非同步方法呼叫上提供的 HTTP 要求進度資訊;訪問有關傳輸的安全通訊端層 (SSL) 詳細資料;在進階應用程式中包含自訂篩選器的功能等。
14.2.1 Get請求擷取字串和資料流資料
(1)擷取字串資料
HttpClient類使用基於任務的非同步模式提供了非常簡化的請求操作,你可以直接調用HttpClient類GetStringAsync方法便可以擷取到網路返回的字串資料。下面來看一下使用Get請求來擷取網路返回的字串,實現的代碼很簡潔和簡單,範例程式碼如下所示:
Uri uri = new Uri("http://yourwebsite.com");
HttpClient httpClient = new HttpClient();
// 擷取網路的返回的字串資料
string result = await httpClient.GetStringAsync (uri);
使用GetStringAsync方法是一種簡化的HTTP請求,如果要擷取到HTTP請求所返回的整個對象HttpResponseMessage類對象可以使用GetAsync方法。HttpResponseMessage對象是HTTP的相應訊息對象,它包含了網路請求相應的HTTP頭、資料體等資訊。下面使用GetAsync方法來擷取網路返回的字串資訊,範例程式碼如下所示:
HttpResponseMessage response = await httpClient.GetAsync(uri);
string responseBody = await response.Content.ReadAsStringAsync();
(2)擷取資料流資料
HttpResponseMessage對象的Content屬性工作表示是返回的資料對象,是一個IHttpContent類型的對象。如果要擷取的是資料流資料,可以通過它的ReadAsBufferAsync方法擷取到返回的IBuffer對象,或者通過ReadAsInputStreamAsync地方擷取IInputStream對象,然後再轉化為Stream對象,範例程式碼如下所示:
using (Stream responseStream = (await response.Content.ReadAsInputStreamAsync()).AsStreamForRead())
{
int read = 0;
byte[] responseBytes = new byte[1000];
do
{
// 如果read等於0表示Stream的資料以及讀取完畢
read = await responseStream.ReadAsync(responseBytes, 0, responseBytes.Length);
} while (read != 0);
}
(3)取消網路請求
HttpClient類發起的網路請求都是基於任務的非同步方法呼叫,所以要取消其非同步操作可以通過非同步任務的取消對象CancellationTokenSource對象來取消,這點和HttpWebRequest類是不同。如果使用CancellationTokenSource對象來取消非同步請求會觸發TaskCanceledException異常,這個異常需要用try catch語句來捕獲,便可以識別到請求是被取消的。
private CancellationTokenSource cts = new CancellationTokenSource();
try
{
// 使用CancellationTokenSource對象來控制非同步任務的取消操作
HttpResponseMessage response = await httpClient.GetAsync(new Uri(resourceAddress)).AsTask(cts.Token);
responseBody = await response.Content.ReadAsStringAsync().AsTask(cts.Token);
cts.Token.ThrowIfCancellationRequested();
}
catch (TaskCanceledException)
{
responseBody = "請求被取消";
}
// 調用Cancel方法取消網路請求
if (cts.Token.CanBeCanceled)
{
cts.Cancel();
}
14.2.2 Post請求發送字串和資料流資料
使用HttpClient類發起Post請求的編程方式也很簡潔,可以調用方法PostAsync(Uri uri, IHttpContent content)來直接向目標的地址Post資料,在該方法裡面有兩個參數其中uri就是網路的目標地址,兩外一個content是指你要向目標地址Post的資料對象。在Post資料之前首先把資料初始化成為一個IHttpContent對象,實現了IHttpContent介面的類有HttpStringContent類、HttpStreamContent類和HttpBufferContent類,這三個類分表代表了字串類型、資料流類型和二進位類型,資料流類型和二進位類型是可以互相轉換的區別不大。調用PostAsync方法之後會返回一個HttpResponseMessage對象,通過這個HTTP的相應訊息對象我們就可以擷取Post請求之後的返回的結果資訊。Post請求發送字串和資料流資料的程式碼範例如下所示:
(1)Post請求發送字串資料
HttpStringContent httpStringContent = new HttpStringContent("hello Windows 10");
HttpResponseMessage response = await httpClient.PostAsync(uri,
httpStringContent).AsTask(cts.Token);
string responseBody = await response.Content.ReadAsStringAsync().AsTask(cts.Token);
(2)Post請求發送資料流資料
HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
HttpResponseMessage response = await httpClient.PostAsync(uri,
streamContent).AsTask(cts.Token);
string responseBody = await response.Content.ReadAsStringAsync().AsTask(cts.Token);
除了使用PostAsync方法之外,還可以使用SendRequestAsync方法來發送網路請求,SendRequestAsync方法既可以使用Get方式也可以使用Post方式。SendRequestAsync方法發送的訊息類型是HttpRequestMessage類對象,HttpRequestMessage類表示HTTP的請求訊息類,你可以通過HttpRequestMessage對象佈建要求的類型(Get/Post)和傳輸的資料對象。使用SendRequestAsync方法的程式碼範例如下所示:
// 建立HttpRequestMessage對象
HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, new Uri(resourceAddress));
request.Content = streamContent;
// 發送資料
HttpResponseMessage response = await httpClient.SendRequestAsync(request).AsTask(cts.Token);
string responseBody = await response.Content.ReadAsStringAsync().AsTask(cts.Token);
14.2.3 設定和擷取Cookie
Cookie是指某些網站為了辨別使用者身份、進行回話跟蹤而儲存在使用者本地終端上的資料(通常經過加密)。當在使用HTTP請求的時候,如果伺服器返回的資料待用Cookie資料,也是可以擷取出來,儲存在本地,下次發起HTTP請求的時候就會帶上這些Cookie的資料。
在HttpClient類的網路請求中可以通過HttpBaseProtocolFilter類來擷取網站的Cookie資訊,HttpBaseProtocolFilter類表示是HttpClient的HTTP請求的基礎協議的過濾器。擷取Cookie的程式碼範例如下所示:
// 建立一個HttpBaseProtocolFilter對象
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
// 通過HttpBaseProtocolFilter對象擷取使用HttpClient進行過網路請求的地址的Cookie資訊
HttpCookieCollection cookieCollection = filter.CookieManager.GetCookies(new Uri(resourceAddress));
// 遍曆整個Cookie集合的Cookie資訊
foreach (HttpCookie cookie in cookieCollection)
{
}
當然在發送HTTP請求的時候也一樣可以帶上Cookie資訊,如果伺服器可以識別到Cookie資訊就會通過Cookie資訊來進行一些操作,比如Cookie資訊資訊帶有使用者名稱和密碼的加密資訊,那麼就可以免去登入的步驟。在HttpClient的網路請求裡面HttpCookie類表示是一個Cookie對象,建立好Cookie對象之後通過HttpBaseProtocolFilter對象的CookieManager屬性來設定Cookie,然後發送網路請求,這時候的網路請求就會把Cookie資訊給帶上。設定Cookie的程式碼範例如下所示:
// 建立一個HttpCookie對象,"id"表示是Cookie的名稱,"localhost"是主機名稱,"/"是表示伺服器的虛擬路徑
HttpCookie cookie = new HttpCookie("id", "yourwebsite.com", "/");
// 設定Cookie的值
cookie.Value = "123456";
// 設定Cookie存活的時間,如果設定為null表示只是在一個會話裡面生效
cookie.Expires = new DateTimeOffset(DateTime.Now, new TimeSpan(0, 1, 8));
// 在過濾器裡面設定Cookie
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
bool replaced = filter.CookieManager.SetCookie(cookie, false);
……接下來可以向"yourwebsite.com"遠程主機發起請求
14.2.4 網路請求的進度監控
HttpClient的網路請求是支援進度監控,通過非同步任務的IProgress<T>對象可以直接監控到HttpClient的網路請求返回的進度資訊,返回的進度對象是HttpProgress類對象。在進度對象HttpProgress裡麵包含了下面的一些資訊:Stage(當前的狀態)、BytesSent(已發送的資料大小)、BytesReceived(已接收的資料大小)、Retries(重試的次數)、TotalBytesToSend(總共需要發送的資料大小)和TotalBytesToReceive(總共需要接收的資料大小)。網路請求進度監控的程式碼範例如下所示:
// 建立IProgress<HttpProgress>對象
IProgress<HttpProgress> progress = new Progress<HttpProgress>(ProgressHandler);
// 在非同步任務中加入進度監控
HttpResponseMessage response = await httpClient.PostAsync(new Uri(resourceAddress), streamContent).AsTask(cts.Token, progress);
// 進度監控的回調方法
private void ProgressHandler(HttpProgress progress)
{
// 在這裡可以通過progress參數擷取到進度的相關資訊
}
14.2.5 自訂HTTP要求篩選器
HTTP要求篩選器是HttpClient網路請求的一個很強大的功能,它可以把你每次網路請求需要規則封裝起來作為一個公用的篩選器來使用,使得特定串連和安全方案的 Web 請求變得更加簡單。我們可以把身分識別驗證、資料加密、串連失敗後使用自動重試等邏輯封裝在篩選器裡面,然後再使用篩選器來初始化一個HttpClient對象進行網路請求。
通常情況下,處理請求期間預期可能會出現的一個網路或安全狀況很容易,但要處理多個網路或安全狀況可能就比較困難。 你可以建立一些簡單的篩選器,然後再根據需要將它們連結起來。這樣你就能夠針對預期可能會出現的複雜情況開發出一些 Web 請求功能,而無需開發非常複雜的程式。
HttpClient是用於通過HTTP發送和接收請求的主類,它使用HttpBaseProtocolFilter類來確定如何發送和接收資料,所以HttpBaseProtocolFilter在邏輯上是所有自訂篩選器鏈的結尾。每個HttpClient執行個體都可以有一個不同的篩選器鏈或管道,14.3所示。
圖14.3 HttpClient請求的篩選器鏈模型
若要編寫一個自訂篩選器,你需要建立一個自訂的篩選器類實現IHttpFilter介面,通過IHttpFilter.SendRequestAsync方法來指定篩選器的工作方式,也就是把你對於網路請求封裝的資訊放在該方法裡面,在發起網路請求的時候篩選器內部會調用該方法。你可以使用 C#、Visual Basic .NET 或 C++ 來編寫篩選器,並且這些篩選器可以在 Windows 運行時支援的所有語言中調用和使用。下面來看一個向 HTTP 要求和響應添加自訂標題的篩選器的範例程式碼。
// 建立一個自訂篩選器使用該篩選器會在HTTP請求和相應中都添加一個自訂的HTTP頭資訊
public class PlugInFilter : IHttpFilter
{
private IHttpFilter innerFilter;
public PlugInFilter(IHttpFilter innerFilter)
{
if (innerFilter == null)
{
throw new ArgumentException("innerFilter cannot be null.");
}
this.innerFilter = innerFilter;
}
// 在SendRequestAsync方法裡面添加自訂的HTTP頭
public IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request)
{
return AsyncInfo.Run<HttpResponseMessage, HttpProgress>(async (cancellationToken, progress) =>
{
// 添加要求標頭
request.Headers.Add("Custom-Header", "CustomRequestValue");
HttpResponseMessage response = await innerFilter.SendRequestAsync(request).AsTask(cancellationToken, progress);
cancellationToken.ThrowIfCancellationRequested();
// 添加相應頭
response.Headers.Add("Custom-Header", "CustomResponseValue");
return response;
});
}
public void Dispose()
{
innerFilter.Dispose();
GC.SuppressFinalize(this);
}
}
若要使用此篩選器,在建立HttpClient對象時將其介面傳遞到HttpClient(IHttpFilter)構造方法裡面。若要設定篩選器鏈,請將新篩選器連結到之前的篩選器以及位於該鏈結尾處的 HttpBaseProtocolFilter對象。下面使用PlugInFilter篩選器來建立HttpClient對象,程式碼範例如下所示:
// 先建立一個HttpBaseProtocolFilter對象,因為這個是HttpClient預設的最底下的篩選器
var basefilter = new HttpBaseProtocolFilter();
// 建立PlugInFilter篩選器對象,連結到HttpBaseProtocolFilter對象上
var myfilter = new PlugInFilter(basefilter);
// 使用自訂的篩選器建立HttpClient對象
HttpClient httpClient = new HttpClient(myfilter);
……下面使用httpClient對象來發起網路請求都會自動帶上自訂篩選器所添加的HTTP頭
本文來源於《深入淺出Windows 10跨平台 app開發》
原始碼下載:http://vdisk.weibo.com/u/2186322691
目錄:http://www.cnblogs.com/linzheng/p/5021428.html
歡迎關注我的微博@WP林政 公眾號:wp開發(號:wpkaifa)
Windows10/WP技術交流群:284783431
[深入淺出WIndows 10]網路編程之HttpClient類