Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

28 May 2020

WindowsBlog读博笔记【一】:UWP的HttpClient API

Demystifying HttpClient APIs in the Universal Windows Platform

用新的System.Net.Http.HttpClient和Windows.Web.Http.HttpClient,不要用老的(比如WebClient 、HttpWebRequest )。System.Net.Http.HttpClient仅支持.Net,跨平台性强;Windows.Web.Http.HttpClient支持所有的WinRT语言,且功能更丰富。

System.Net.Http.HttpClien在.NET 4.5中引入,这个包是基于Windows.Web.Http和WinINet的。

Windows.Web.Http.HttpClient在Windows8.1引入,底层实现是基于WinINet 。

System.Net.Http

核心是HttpClient对象,这个对象可以发送多条请求(HttpRequestMessage)。HttpContent用来表征HTTP的消息内容。HttpContent的派生类(比如StreamContent、MultipartContent以及StringContent)可以用来处理特定的HTTP消息内容。HttpContent以及它的派生类都支持ReadAs方法,将消息内容作为字符串,字节数组或者流来处理。

HttpClient对象带有一个控把对象,用来表征所有根HTTP相关的设置。默认控把对象的类型是HttpClientHandler。如果像自定义HTTP相关的设置,需要自己实例化HttpClientHandler,更改对象相应的设置,然后传给HttpClient:

在HttpClient和HttpClientHandler之间,可以插入多个 DelegatingHandler 的对象,用来对请求和回复消息进行自定义处理。 DelegatingHandler 的InnerHandler 用来链接下一个DelegatingHandler 对象。

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

Windows.Web.Http

Windows.Web.Http和System.Net.Http类似,不过前者把控把叫做过滤器。

一些对比

··· HTTP client role aspect System.Net.Http type Corresponding Windows.Web.Http type Client entity HttpClient HttpClient HTTP request HttpRequestMessage HttpRequestMessage HTTP response HttpResponseMessage HttpResponseMessage Entity body of an HTTP request or response HttpContent IHttpContent Representations of HTTP content as string/stream/etc. StringContent, StreamContent and ByteArrayContent HttpStringContent, HttpStreamContent and HttpBufferContent respectively HTTP stack/settings HttpClientHandler HttpBaseProtocolFilter Base class/interface for creating custom handlers/filters DelegatingHandler IHttpFilter ···

一些常用的场景

修改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");

HttpClient.DefaultRequestHeaders 返回操作系统默认的HTTP信息头

超时设置

System.Net.Http:

// client级别的超时设置
myClient.Timeout = TimeSpan.FromSeconds(30);

// 消息级别并没有超时设置,需要设置异步操作的时长来模拟

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没有client级别的超时设置。

验证信息

System.Net.Http:

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

Windows.Web.Http:

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

Windows.Web.Http:会自动弹出一个UI对话框让用户输入密码,如果不需要这个对话框,那么需要将HttpBaseProtocolFilter 的AllowUI 设置为false。

证书信息

默认情况下,HttpClient不会将用户证书发给服务端,如果需要发送,则要在代码中指定。

System.Net.Http:

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

Windows.Web.Http:

默认情况下会弹出UI让用户选择,不过也可以在代码指定。

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

在使用用户证书之前,用户证书必须被加入app的certificate store,需要参考这些指令

HttpClientHandler.ClientCertificateOptions有两个选项:Automatic和Manual。Automatic会自动发送服务器要求的证书,而Manual则不会。

代理设置

不管是System.Net.Http还是Windows.Web.Http,都可以自动从IE/Edge的代理设置中获取代理信息。通过设置 HttpClientHandler.UseProxy为false;或者HttpBaseProtocolFilter.UseProxy为false,可以避免使用默认代理。但是这两个API都没有提供自定的代理设置。

Cookie设置

默认情况下,这两个API都会保存服务器发送的代理,并将其包含在后续的请求消息中。通过设置 HttpClientHandler.UseCookies为false;或者HttpBaseProtocolFilter.CookieUsageBehavior为HttpCookieUsageBehavior.NoCookies可以禁止此行为。

System.Net.Http:

	
// 手动设置一个client级别的cookie
myClientHandler.CookieContainer.Add(resourceUri, myCookie);

// 设置消息级别的cookie
HttpRequestMessage myRequest = new HttpRequestMessage();
myRequest.Headers.Add("Cookie", "user=foo; key=bar");

// 查看设置的cookie	
var cookieCollection = myClientHandler.CookieContainer.GetCookies(resourceUri);

Windows.Web.Http:

	
// Add a cookie manually.
filter.CookieManager.SetCookie(myCookie);

// Get all cookies for a given URI.
var cookieCollection = filter.CookieManager.GetCookies(resourceUri);
 
// Delete a cookie.
filter.CookieManager.DeleteCookie(myCookie);

Windows.Web.Http会将cookie在多个使用WinINet的api中共享,比如Windows.Web.Syndication, Windows.Web.AtomPub, XHR等等。

最大单个服务器连接数量

默认情况下,对于单个服务器可以建立6个HTTP连接。System.Net.Http HttpClient没有办法修改这个选项,但是 Windows.Web.Http 可以:

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

HTTP/2的支持

两个API都提供对HTTP/2的支持。

(草草收尾)

2020-06-02更新

Allowing Untrusted SSL Certificates with HttpClient学到,通过下面的方式可以忽略自己生成的证书错误问题:

var filter = new HttpBaseProtocolFilter();
#if DEBUG
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
#endif

Certificate Pinning on UWP学到,使用HttpBaseProtocolFilter.ServerCustomValidationRequested可以对证书增加自定义的验证步骤。

(更新完)

comments powered by Disqus