閱讀目錄:web
做爲一個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
其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 API的對象模型跟上面描述的System.Net.Http版本很是 ,它也有client entity的概念,一個處理器(在這叫「filter」過濾器),及在client和系統默認過濾器之間選擇是否插入自定義邏輯。
其大多數類型是直接相似於System.Net.Http的類型的,以下:
在上面關於System.Net.Http API的鏈式處理器討論,也可應用於Windows.Web.Http API,這裏你能夠建立自定義鏈式過濾器,傳遞它們到HttpClient對象的構造函數中。
關於HttpClient APIs中的大多數HTTP功能的通用實現,都能在網上或書上找到一些代碼片斷和相應介紹說明。關於完整的細節和指導,請查看Windows.Web.Http.HttpClient和System.Net.Http.HttpClient API各自的MSDN文檔。
在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 API。
一些頭部是用集合表示的,要使添加和移除方法去編輯它們。
HttpClient.DefaultRequestHeaders屬性表示默認頭部集合,它會在App層添加到頭部。請求會在操做系統協議棧上被處理,附加的頭部會在數據經過網卡發送以前被添加。
在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.HttpClient上沒有超時屬性,所以,必須使用上面介紹的刪除token方式實現超時功能。
爲了保護用戶憑據信息,默認狀況下Http協議棧在請求發出時,不能添加任務身份驗證信息。如須要使用指定用戶驗證,使用下面的模式:
var myClientHandler = new HttpClientHandler(); myClientHandler.Credentials = new NetworkCredential(myUsername, myPassword);
對於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等值。
爲了保護用戶憑據信息,默認狀況下API不會發送任何客戶端憑據到服務器上。 使用客戶端憑據認證代碼以下:
var myClientHandler = new HttpClientHandler();
myClientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
使用客戶端憑據認證有兩個選項,默認是提供UI給用戶選擇一個證書信息。做爲一種選擇,你能夠用程序設置一個客戶端證書,以下:
var myFilter = new HttpBaseProtocolFilter(); myFilter.ClientCertificate = myCertificate;
爲在兩者API中任意一個使用客戶端證書,你必須添加它到app的證書商店裏,參考鏈接的這些構造。在「My」中企業APP也能使用已經存在的客戶端證書。
對於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。
默認狀況下,兩者APIs都保存經過服務器發送的cookies,在相同的app容器內,自動添加上Cookies到那個URL的後續請求上。 這些Cookies被那個明確的URL讀取, 添加新的自定義cookies。 兩者APIs都有一個選項能禁止發送cookies到服務器上:在System.Net.Http上設置HttpClientHandler.UseCookies爲false,在Windows.Web.Http設置HttpBaseProtocolFilter.CookieUsageBehavior爲HttpCookieUsageBehavior.NoCookies。
在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);
經過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相關開發。