欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-01-05 15:38:28
阅读目录:概述如何选择System.Net.HttpWindows.Web.HttpHTTP的常用功能修改http头部设置超时使用身份验证凭据使用客户端证书cookie处理概述作为一个Universal Windows Platform (UWP)开发者,如果你尝试使用http与web服务或其他服务... ......

阅读目录:

概述 如何选择 System.Net.Http Windows.Web.Http HTTP的常用功能 修改http头部 设置超时 使用身份验证凭据 使用客户端证书 cookie处理 概述

作为一个Universal Windows Platform (UWP)开发者,如果你尝试使用http与web服务或其他服务端通讯时,有多个API可以选择。 UWP中最常见并推荐使用的HTTP客户端API实现是System.Net.Http.HttpClient和Windows.Web.Http.HttpClient。 这些APIs相比旧的应该优先使用,比如旧APIs的WebClient和HttpWebRequest(尽管它的子集在UWP中是向后兼容的)。

我们收到一些关于问题反馈,关于这些APIs不同之处,从功能上来说两组APIs是上相等的,那在不同场景下选择哪一个呢,诸如此类的问题。 在这篇文章中,我们会去尝试定位这些问题,理清楚这两组APIs的用途及使用场景。

第一个推荐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时,其支持的系统版本和程序语言如下所示:

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

如何选择

在UWP中这些HTTP API都是可以使用的,对于开发者来说最大的问题是在APP中应该使用哪一个。其答案取决去几个因素:

是否需要结合本地UI收集用户证书,控制HTTP缓存读和写,或者通过指定的ssl客户端证书去做认证? 如果需要认证,那是应使用Windows.Web.Http.HttpClient。在现在的UWP中,Windows.Web.Http提供HTTP设置,它比System.Net.Http API更好的控制这些。 在未来的版本,也会加强支持System.Net.Http在UWP中的特性。

是否考虑写跨平台的.NET代码(跨UWP/ASP.NET 5/IOS和Android)? 如果需要,那使用System.Net.Http API。它可以让你写的代码复用在其他.Net平台上,比如ASP.Net 5和.NET桌面平台应用。 通过使用Xamarin,这些API在IOS和Android中也得到支持。

现在就比较好理解为什么会有两个相似APIs了,也了解怎么在二者之间进行选择,下面进一步了解这两个对象模型。

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协议栈上。 从概念上来看如下图:

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

下面是完成这部分的例子代码:

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的类型的,如下:

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

在上面关于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;
说明:

为在二者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。

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相关开发。

上一篇:

下一篇: