揭祕Windows10 UWP中的httpclient接口[2]

閱讀目錄:web

  1. 概述
  2. 如何選擇
  3. System.Net.Http
  4. Windows.Web.Http
  5. HTTP的經常使用功能
  6. 修改http頭部
  7. 設置超時
  8. 使用身份驗證憑據
  9. 使用客戶端證書
  10. cookie處理

概述

做爲一個Universal Windows Platform (UWP)開發者,若是你嘗試使用http與web服務或其餘服務端通信時,有多個API能夠選擇。 UWP中最多見並推薦使用的HTTP客戶端API實現是System.Net.Http.HttpClient和Windows.Web.Http.HttpClient。 這些APIs相比舊的應該優先使用,好比舊APIs的WebClient和HttpWebRequest(儘管它的子集在UWP中是向後兼容的)。windows

咱們收到一些關於問題反饋,關於這些APIs不一樣之處,從功能上來講兩組APIs是上相等的,那在不一樣場景下選擇哪個呢,諸如此類的問題。 在這篇文章中,咱們會去嘗試定位這些問題,理清楚這兩組APIs的用途及使用場景。api

第一個推薦AIP是System.Net.Http.HttpClient,它在Net 4.5中第一次出現,經過Nuget能夠安裝這個API的兼容版本,這樣就能夠在Net 4.0和windows Phone 8 Silverlight apps中使用。相比舊的HttpWebRequest API,這個API的目標是提供一個簡單的,乾淨的抽象層,比較靈活的實現http客戶端功能。 好比,它容許連接自定義處理器,開發者能夠攔截每一個request和response,去實現自定義邏輯。 在windows8.1以後,全部功能都在.NET下面實現。 在windows10 UWP中這個API實現移到Windows.Web.Http和WinINet Http層上。數組

另一個推薦API是Windows.Web.Http.HttpClient,這個API是Windows 8.1時開始引進的,在Windows Phone 8.1也是可使用的。 增長這個API的主要目是,把不一樣windows應用開發語言(C#, VB, C++, JavaScript)下,不一樣Http APIs合成一個,它支持上述APIs的全部特性。 大多數基礎API都是從System.Net.Http派生的,在Windows HTTP基礎上實現。瀏覽器

在Windows商店APP中使用這些API時,其支持的系統版本和程序語言以下所示:緩存

如何選擇

在UWP中這些HTTP API都是可使用的,對於開發者來講最大的問題是在APP中應該使用哪個。其答案取決去幾個因素:服務器

  • 是否須要結合本地UI收集用戶證書,控制HTTP緩存讀和寫,或者經過指定的ssl客戶端證書去作認證? 若是須要認證,那是應使用Windows.Web.Http.HttpClient。在如今的UWP中,Windows.Web.Http提供HTTP設置,它比System.Net.Http API更好的控制這些。 在將來的版本,也會增強支持System.Net.Http在UWP中的特性。cookie

  • 是否考慮寫跨平臺的.NET代碼(跨UWP/ASP.NET 5/IOS和Android)? 若是須要,那使用System.Net.Http API。它可讓你寫的代碼複用在其餘.Net平臺上,好比ASP.Net 5和.NET桌面平臺應用。 經過使用Xamarin,這些API在IOS和Android中也獲得支持。網絡

如今就比較好理解爲何會有兩個類似APIs了,也瞭解怎麼在兩者之間進行選擇,下面進一步瞭解這兩個對象模型。app

System.Net.Http

其HttpClient對象是最頂端的抽象模型,在HTTP協議client-server模型中它表示client這部分。其client能發出多個request請求(用HttpRequestMessage表示)到服務端上,從服務端接收響應(用HttpResponseMessage表示)。用HttpContent基類和它派生出的類,表示對象body和每一個request或response的content頭部,好比StreamContent,MultipartContent和StringContent。它們表示各類http實體body內容。這些類都會提供ReadAs開頭的一組方法,它能從請求或響應實體body中,以字符串形式、字節數組、流形式讀取內容。

每個HttpClient對象下都有一個處理者對象,它表示client下全部與HTTP相關的配置。從概念上來講,能夠認爲它是client部分下HTTP協議棧的表明。在客戶端發送HTTP請求到服務端和傳輸數據到客戶端上,它是很是可靠的。

在System.Net.Http API中默認處理者是HttpClientHandler。當你建立HttpClient對象實例時,會使用默認HTTP stack設置,自動幫你建立一個HttpClientHandler。若是你想修改默認一些設置,好比緩存行爲,自動壓縮,證書或代理,能夠直接建立一個HttpClientHandler實例,修改它的屬性,把它當作HttpClient構造函數的參數傳入。這樣HttpClient對象就會使用咱們自定義的處理器,以下:

HttpClientHandler myHandler = new HttpClientHandler(); 
myHandler.AllowAutoRedirect = false;
HttpClient myClient = new HttpClient(myHandler);

鏈式處理器

System.Net.Http.HttpClient API設計中一個重要優點是:可以插入自定義處理器、在HttpClient對象下建立一連串的處理器。例如:構建一個app,它從web服務中請求一些數據。這時就能夠自定義邏輯去處理HTTP服務端響應的4xx (客戶端錯誤)和5xx (服務端錯誤),使用具體的重試步驟,好比嘗試不一樣的端口請求或添加一個用戶認證。 還可能會想從業務邏輯部分分離出HTTP相關的工做,它只關心web服務的數據返回。

這就可使用自定義處理器類來完成,它從DelegatingHandler派生出,例如CustomHandler1,而後建立一個新實例,把它傳入HttpClient構造函數。 DelegatingHandler類的InnerHandler屬性被用指定下一個處理器,好比,能夠添加個新的自定處理器(例CustomHandler2)處處理鏈上。處理鏈上最後一個處理者的InnerHandler,能夠設置成HttpClientHandler的實例,它將傳遞請求到系統的HTTP協議棧上。 從概念上來看以下圖:

下面是完成這部分的例子代碼:

public class CustomHandler1 : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("Processing request in Custom Handler 1");
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
        Debug.WriteLine("Processing response in Custom Handler 1");
        return response;
    }
}
public class CustomHandler2 : DelegatingHandler
{
    // Similar code as CustomHandler1.
}
public class Foo
{
    public void CreateHttpClientWithChain()
    {
        HttpClientHandler systemHandler = new HttpClientHandler();
        CustomHandler1 myHandler1 = new CustomHandler1();
        CustomHandler2 myHandler2 = new CustomHandler2();
 
        // Chain the handlers together.
        myHandler1.InnerHandler = myHandler2;
        myHandler2.InnerHandler = systemHandler;
 
        // Create the client object with the topmost handler in the chain.
        HttpClient myClient = new HttpClient(myHandler1);
    }
}

說明:

若是你試圖發送一個請求到遠程服務器端口上,其鏈上最後的處理器一般是HttpClientHandler,它實際是從系統HTTP協議棧層面發送這個請求或接收這個響應。做爲一種選擇,可使用一個模擬處理器,模擬發送請求到服務器上,返回一個僞造的響應,這能夠用來單元測試。

在傳遞請求到內部處理器以前或響應處理器之上,添加一個處理邏輯,能減小性能消耗。這個處理器場景下,最好能避免使用耗時的同步操做。

關於鏈式處理概念的詳細信息,能夠看Henrik Nielsen的這篇博客,(注意文章參考的是ASP.NET Web API的API版本。它和本文討論的.NET framework有一些細微的不一樣,但在鏈式處理器上的概念是同樣的)

Windows.Web.Http

Windows.Web.Http API的對象模型跟上面描述的System.Net.Http版本很是 ,它也有client entity的概念,一個處理器(在這叫「filter」過濾器),及在client和系統默認過濾器之間選擇是否插入自定義邏輯。

其大多數類型是直接相似於System.Net.Http的類型的,以下:

在上面關於System.Net.Http API的鏈式處理器討論,也可應用於Windows.Web.Http API,這裏你能夠建立自定義鏈式過濾器,傳遞它們到HttpClient對象的構造函數中。

HTTP的經常使用功能

關於HttpClient APIs中的大多數HTTP功能的通用實現,都能在網上或書上找到一些代碼片斷和相應介紹說明。關於完整的細節和指導,請查看Windows.Web.Http.HttpClient和System.Net.Http.HttpClient API各自的MSDN文檔。

修改頭部

System.Net.Http:

在HttpClient實例上修改全部請求的頭部,使用下面的方式:

var myClient = new HttpClient(); 
myClient.DefaultRequestHeaders.Add("X-HeaderKey", "HeaderValue");
myClient.DefaultRequestHeaders.Referrer = new Uri("http://www.contoso.com");

 只修改指定請求的頭部,使用:

HttpRequestMessage myrequest = new HttpRequestMessage(); 
myrequest.Headers.Add("X-HeaderKey", "HeaderValue");
myrequest.Headers.Referrer = new Uri("http://www.contoso.com");

 Windows.Web.Http:

上面的方式一樣適用於Windows.Web.Http API。

說明

一些頭部是用集合表示的,要使添加和移除方法去編輯它們。

HttpClient.DefaultRequestHeaders屬性表示默認頭部集合,它會在App層添加到頭部。請求會在操做系統協議棧上被處理,附加的頭部會在數據經過網卡發送以前被添加。

設置超時

System.Net.Http:

在the System.Net.Http API中,有兩個方式去設置超時。 在client部分上設置全部請求的超時時間,使用:

myClient.Timeout = TimeSpan.FromSeconds(30);

 在單個請求上設置超時,使用刪除token方式:

var cts = new CancellationTokenSource(); 
cts.CancelAfter(TimeSpan.FromSeconds(30));
var httpClient = new HttpClient();
var resourceUri = new Uri("http://www.contoso.com"); try {
HttpResponseMessage response = await httpClient.GetAsync(resourceUri, cts.Token);
} catch (TaskCanceledException ex)
{ // Handle request being canceled due to timeout. } catch (HttpRequestException ex) { // Handle other possible exceptions. }

 Windows.Web.Http:

在Windows.Web.Http.HttpClient上沒有超時屬性,所以,必須使用上面介紹的刪除token方式實現超時功能。

使用身份驗證憑據

System.Net.Http:

爲了保護用戶憑據信息,默認狀況下Http協議棧在請求發出時,不能添加任務身份驗證信息。如須要使用指定用戶驗證,使用下面的模式:

var myClientHandler = new HttpClientHandler(); 
myClientHandler.Credentials = new NetworkCredential(myUsername, myPassword);

Windows.Web.Http:

對於Windows.Web.Http API,默認狀況下,若是發出的請求是一個資源請求,會提供一個UI對話框,它要求用戶進行確認。如想禁用這個UI對話框,設置HttpBaseProtocolFilter的屬性AllowUI爲false。 使用指定的驗證替代:

var myFilter = new HttpBaseProtocolFilter(); 
myFilter.ServerCredential = new PasswordCredential(「fooBar」, myUsername, myPassword);

說明

  • 在上面的例子中,myUsername和myPassword是一個string字符串變量,一般是從用戶UI輸入或app配置設置中得到。

  • 在UWP應用中,HttpClientHandler.Credentials能被設置爲NULL,DefaultCredentials,類型NetworkCredential等值。

使用客戶端證書

System.Net.Http:

爲了保護用戶憑據信息,默認狀況下API不會發送任何客戶端憑據到服務器上。 使用客戶端憑據認證代碼以下:

var myClientHandler = new HttpClientHandler(); 
myClientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;

Windows.Web.Http:

使用客戶端憑據認證有兩個選項,默認是提供UI給用戶選擇一個證書信息。做爲一種選擇,你能夠用程序設置一個客戶端證書,以下:

var myFilter = new HttpBaseProtocolFilter(); 
myFilter.ClientCertificate = myCertificate;

說明:

  1. 爲在兩者API中任意一個使用客戶端證書,你必須添加它到app的證書商店裏,參考鏈接的這些構造。在「My」中企業APP也能使用已經存在的客戶端證書。

  2. 對於HttpClientHandler.ClientCertificateOptions來講,這有兩個值能夠設置:Automatic和Manual。設置Automatic會從APP證書商店裏選擇一個最匹配的客戶端證書,用它來認證。設置Manual會確保不會發送客戶端證書,即便服務器請求它。

代理設置

對與兩者APis來講,代理設置會自動從IE/Edge瀏覽器中得到,它被全部的Http請求默認調用。這確保了,即便用戶經過一個代理上網,也能自動鏈接工做。 兩者API都不能再APP中提供一種方式去指定一個自定義的代理。不論如何,你能夠選擇設置HttpClientHandler.UseProxy(System.Net.Http中)爲false不使用默認代理設置,在Windows.Web.Http設置HttpBaseProtocolFilter.UseProxy爲false。

cookie處理

默認狀況下,兩者APIs都保存經過服務器發送的cookies,在相同的app容器內,自動添加上Cookies到那個URL的後續請求上。 這些Cookies被那個明確的URL讀取, 添加新的自定義cookies。 兩者APIs都有一個選項能禁止發送cookies到服務器上:在System.Net.Http上設置HttpClientHandler.UseCookies爲false,在Windows.Web.Http設置HttpBaseProtocolFilter.CookieUsageBehavior爲HttpCookieUsageBehavior.NoCookies。

System.Net.Http:

在client處理器上,添加一個cookie到全部的請求上:

// 手工添加一個cookie 
myClientHandler.CookieContainer.Add(resourceUri, myCookie);

添加一個cookie到單個請求上:

HttpRequestMessage myRequest = new HttpRequestMessage(); 
myRequest.Headers.Add("Cookie", "user=foo; key=bar");

檢查一個指定URI的全部Cookies: 

var cookieCollection = myClientHandler.CookieContainer.GetCookies(resourceUri);

Windows.Web.Http:

經過client,添加一個cookie到全部的發送請求上:

// 手工添加一個cookie 
filter.CookieManager.SetCookie(myCookie);

添加一個cookie到單個請求上,這個模式使用和上面的Windows.Web.Http API上是相同的。

管理cookies:

// 從一個指定URI上獲取全部的cookies。
 var cookieCollection = filter.CookieManager.GetCookies(resourceUri);
// 刪除一個cookie。
 filter.CookieManager.DeleteCookie(myCookie);

補充:

Windows.Web.Http API中,對於這幾個APIs來講,cookie管理器中的這些cookies都是共享的,由於它們都是在WinINet棧上實現的,好比:Windows.Web.Syndication, Windows.Web.AtomPub, XHR和其餘的。所以不管使用哪一個api,都能經過服務器對請求的響應中得到cookie, 也可能會添加cookie到一個後續的HttpClient請求中,到一樣的服務器中。 

每臺服務器的最大鏈接數

在操做系統的HTTP協議棧下,對每臺服務器默認鏈接數是6。System.Net.Http HttpClient API不能提供一個方式去控制它,但在Windows.Web.Http API下是能夠的,使用:

var myFilter = new HttpBaseProtocolFilter();
 myFilter.MaxConnectionsPerServer = 15;

最新更新

在windows10 UWP apps中,兩者APIs都添加了對HTTP/2的默認支持。做爲一個開發者,能夠很好的利用這些優點,好比不須要代碼變更就能下降延遲。 兩者APIs(System.Net.Http和Windows.Web.Http)也容許明確禁止這項特性和強制使用HTTP 1.1或1.0.

從目前開始,我嘗試繼續添加一些高級請求特性,好比自定義服務器ssl證書的生效,在全部的地方都能添加處理器/過濾器到HttpClient對象上。爲了在windows上寫出優秀的apps,咱們很期待聽到你須要在這些API上增長新特性。 你也能夠在UserVoice提出想法。也能夠加入 Windows Insiders program ,經過論壇或Windows Feedback app提交反饋。

這篇博客是微軟網絡APIs團隊成員Sidharth Nabar寫的。

譯自 http://blogs.windows.com/buildingapps/2015/11/23/demystifying-httpclient-apis-in-the-universal-windows-platform/

題外話

這篇在上月底翻譯的,一直沒來得及整理。新工做在張江,原先住的太遠單程一小時多,而後找房子、搬家、新工做環境適應。本準備要作win10開發,因此邊研究win10邊翻譯了幾篇,後來調整爲優先桌面開發,開始研究hybird相關開發。

相關文章
相關標籤/搜索