前言

    在上篇文章[ASP.NET Core中的响应压缩]中我们谈到了在ASP.NET Core服务端处理关于响应压缩的请求,服务端的主要工作就是根据Content-Encoding头信息判断采用哪种方式压缩并返回。之前在群里有人问道过,现在的网络带宽这么高了还有必要在服务端针对请求进行压缩吗?确实,如今分布式和负载均衡技术这么成熟,很多需要处理高并发大数据的场景都可以通过增加服务器节点来进行。但是,在资源受限的情况下,或者是还没必要为了某一个点去增加新的服务器节点的时候,我们还是要采用一些程序本身的常规处理手段来进行处理。笔者个人认为响应压缩的使用场景是这样的,在带宽压力比较紧张的情况,且CPU资源比较充足的情况下,使用响应压缩整体效果还是比较明显的。
    有压缩就有解压,而解压的工作就是在请求客户端处理的。比如浏览器,这是我们最常用的Http客户端,许多浏览器都是默认在我们发出请求的时候(比如我们浏览网页的时候)在Request Head中添加Content-Encoding,然后根据响应信息处理相关解压。这些都源于浏览器已经内置了关于请求压缩和解压的机制。类似的还有许多,比如常用的代理抓包工具Filder也是内置这种机制的。只不过需要手动去处理,但实现方式都是一样的。有时候我们在自己写程序的过程中也需要使用这种机制,在传统的.Net HttpWebRequest类库中,并没有这种机制,后来版本中加入了HttpClient,有自带的机制可以处理这种操作,.Net Core作为后起之秀直接将HttpClient扶正,并且在此基础上改良了HttpClientFactory,接下来我们就来探究一下在.Net Core中使用HttpClient处理响应压缩的机制。

使用方式

首先我们来看一下直接在HttpClient中如何处理响应压缩

//自定义HttpClientHandler实例HttpClientHandler httpClientHandler = new HttpClientHandler{    AutomaticDecompression = DecompressionMethods.GZip};//使用传递自定义HttpClientHandler实例的构造函数using (HttpClient client = new HttpClient(httpClientHandler)){    var response = await client.GetAsync($"http://MyDemo/Home/GetPerson?userId={userId}");}

这个操作还是非常简单的,我们操作的并不是HttpClient的属性而是HttpClientHandler中的属性,我们在之前的文章[.NET Core HttpClient源码探究]中曾探讨过,HttpClient的本质其实就是HttpMessageHandler,而HttpClient真正使用到的是HttpMessageHandler最重要的一个子类HttpClientHandler,所有的请求操作都是通过HttpMessageHandler进行的。我们可以看到AutomaticDecompression接受的是DecompressionMethods枚举,既然是枚举就说明包含了不止一个值,接下来我们查看DecompressionMethods中的源码

[Flags]public enum DecompressionMethods{    // 使用所有压缩解压缩算法。    All = -1,    // 不使用解压    None = 0x0,    // 使用gzip解压算法    GZip = 0x1,    // 使用deflate解压算法    Deflate = 0x2,    // 使用Brotli解压算法    Brotli = 0x4}

该枚举默认都是针对常用输出解压算法,接下来我们看一下在HttpClientFactory中如何处理响应压缩。在之前的文章[.NET Core HttpClientFactory+Consul实现服务发现]中我们曾探讨过HttpClientFactory的大致工作方式默认PrimaryHandler传递的就是HttpClientHandler实例,而且在我们注册HttpClientFactory的时候是可以通过ConfigurePrimaryHttpMessageHandler自定义PrimaryHandler的默认值,接下来我们具体代码实现

services.AddHttpClient("mydemo", c =>{    c.BaseAddress = new Uri("http://MyDemo/");}).ConfigurePrimaryHttpMessageHandler(provider=> new HttpClientHandler{    AutomaticDecompression = DecompressionMethods.GZip});

其实在注册HttpClientFactory的时候还可以使用自定义的HttpClient,具体的使用方式是这样的

services.AddHttpClient("mydemo", c =>{    c.BaseAddress = new Uri("http://MyDemo/");}).ConfigureHttpClient(provider => new HttpClient(new HttpClientHandler{    AutomaticDecompression = DecompressionMethods.GZip}));

HttpClient确实帮我们做了好多事情,只需要简单的配置一下就开启了针对响应压缩的处理。这更勾起了我们对HttpClient的探讨,接下来我们就通过源码的方式查看它是如何发起可响应压缩请求,并解压响应结果的。

源码探究

通过上面的使用方式我们得知,无论使用哪种形式,最终都是针对HttpClientHandler做配置操作,接下来我们查看HttpClientHandler类[点击查看源码