欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.Net Core HttpClient處理響應(yīng)壓縮詳細(xì)

 更新時(shí)間:2021年09月27日 11:07:26   作者:作者yi念之間  
.Net Core作為后起之秀直接將HttpClient扶正,并且在此基礎(chǔ)上改良了HttpClientFactory,接下來(lái)我們就來(lái)探究一下在.Net Core中使用HttpClient處理響應(yīng)壓縮的機(jī)制。,需要的朋友可以參考下面文章的具體內(nèi)容

前言:

  在之前的文章ASP.NET Core中的響應(yīng)壓縮的實(shí)現(xiàn)提到,服務(wù)端的主要工作就是根據(jù)Content-Encoding頭信息判斷采用哪種方式壓縮并返回。之前在群里有人問(wèn)道過(guò),現(xiàn)在的網(wǎng)絡(luò)帶寬這么高了還有必要在服務(wù)端針對(duì)請(qǐng)求進(jìn)行壓縮嗎?確實(shí),如今分布式和負(fù)載均衡技術(shù)這么成熟,很多需要處理高并發(fā)大數(shù)據(jù)的場(chǎng)景都可以通過(guò)增加服務(wù)器節(jié)點(diǎn)來(lái)進(jìn)行。但是,在資源受限的情況下,或者是還沒(méi)必要為了某一個(gè)點(diǎn)去增加新的服務(wù)器節(jié)點(diǎn)的時(shí)候,我們還是要采用一些程序本身的常規(guī)處理手段來(lái)進(jìn)行處理。筆者個(gè)人認(rèn)為響應(yīng)壓縮的使用場(chǎng)景是這樣的,在帶寬壓力比較緊張的情況,且CPU資源比較充足的情況下,使用響應(yīng)壓縮整體效果還是比較明顯的。
    有壓縮就有解壓,而解壓的工作就是在請(qǐng)求客戶(hù)端處理的。比如瀏覽器,這是我們最常用的Http客戶(hù)端,許多瀏覽器都是默認(rèn)在我們發(fā)出請(qǐng)求的時(shí)候(比如我們?yōu)g覽網(wǎng)頁(yè)的時(shí)候)在Request Head中添加Content-Encoding,然后根據(jù)響應(yīng)信息處理相關(guān)解壓。這些都源于瀏覽器已經(jīng)內(nèi)置了關(guān)于請(qǐng)求壓縮和解壓的機(jī)制。類(lèi)似的還有許多,比如常用的代理抓包工具Filder也是內(nèi)置這種機(jī)制的。只不過(guò)需要手動(dòng)去處理,但實(shí)現(xiàn)方式都是一樣的。有時(shí)候我們?cè)谧约簩?xiě)程序的過(guò)程中也需要使用這種機(jī)制,在傳統(tǒng)的.Net HttpWebRequest類(lèi)庫(kù)中,并沒(méi)有這種機(jī)制,后來(lái)版本中加入了HttpClient,有自帶的機(jī)制可以處理這種操作,

一、使用方式

首先我們來(lái)看一下直接在HttpClient中如何處理響應(yīng)壓縮

//自定義HttpClientHandler實(shí)例
HttpClientHandler httpClientHandler = new HttpClientHandler
{
    AutomaticDecompression = DecompressionMethods.GZip
};
//使用傳遞自定義HttpClientHandler實(shí)例的構(gòu)造函數(shù)
using (HttpClient client = new HttpClient(httpClientHandler))
{
    var response = await client.GetAsync($"http://MyDemo/Home/GetPerson?userId={userId}");
}


這個(gè)操作還是非常簡(jiǎn)單的,我們操作的并不是HttpClient的屬性而是HttpClientHandler中的屬性,我們?cè)谥暗奈恼耓.NET Core HttpClient源碼探究]中曾探討過(guò),HttpClient的本質(zhì)其實(shí)就是HttpMessageHandler,而HttpClient真正使用到的是HttpMessageHandler最重要的一個(gè)子類(lèi)HttpClientHandler,所有的請(qǐng)求操作都是通過(guò)HttpMessageHandler進(jìn)行的。我們可以看到AutomaticDecompression接受的是DecompressionMethods枚舉,既然是枚舉就說(shuō)明包含了不止一個(gè)值,接下來(lái)我們查看DecompressionMethods中的源碼

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


該枚舉默認(rèn)都是針對(duì)常用輸出解壓算法,接下來(lái)我們看一下在HttpClientFactory中如何處理響應(yīng)壓縮。在之前的文章[.NET Core HttpClientFactory+Consul實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)]中我們?cè)接戇^(guò)HttpClientFactory的大致工作方式默認(rèn)PrimaryHandler傳遞的就是HttpClientHandler實(shí)例,而且在我們注冊(cè)HttpClientFactory的時(shí)候是可以通過(guò)ConfigurePrimaryHttpMessageHandler自定義PrimaryHandler的默認(rèn)值,接下來(lái)我們具體代碼實(shí)現(xiàn)

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


其實(shí)在注冊(cè)HttpClientFactory的時(shí)候還可以使用自定義的HttpClient,具體的使用方式是這樣的

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


HttpClient確實(shí)幫我們做了好多事情,只需要簡(jiǎn)單的配置一下就開(kāi)啟了針對(duì)響應(yīng)壓縮的處理。這更勾起了我們對(duì)HttpClient的探討,接下來(lái)我們就通過(guò)源碼的方式查看它是如何發(fā)起可響應(yīng)壓縮請(qǐng)求,并解壓響應(yīng)結(jié)果的。

二、源碼探究

通過(guò)上面的使用方式我們得知,無(wú)論使用哪種形式,最終都是針對(duì)HttpClientHandler做配置操作,接下來(lái)我們查看HttpClientHandler類(lèi)中AutomaticDecompression屬性的代碼

public DecompressionMethods AutomaticDecompression
{
    get => _underlyingHandler.AutomaticDecompression;
    set => _underlyingHandler.AutomaticDecompression = value;
}

它本身的值操作來(lái)自_underlyingHandler這個(gè)對(duì)象,也就是說(shuō)讀取和設(shè)置都是在操作_underlyingHandler.AutomaticDecompression,我們查找到_underlyingHandler對(duì)象的聲明位置

private readonly SocketsHttpHandler _underlyingHandler;

這里說(shuō)明一下,HttpClient的實(shí)質(zhì)工作類(lèi)是HttpClientHandler,而HttpClientHandler真正發(fā)起請(qǐng)求是依靠的SocketsHttpHandler這個(gè)類(lèi),也就是說(shuō)SocketsHttpHandler是最原始發(fā)起請(qǐng)求的類(lèi)。HttpClientHandler本質(zhì)還是通過(guò)SocketsHttpHandler發(fā)起的Http請(qǐng)求,接下來(lái)我們就查看SocketsHttpHandler類(lèi)是如何處理AutomaticDecompression這個(gè)屬性的

public DecompressionMethods AutomaticDecompression
{
    get => _settings._automaticDecompression;
    set
    {
        CheckDisposedOrStarted();
        _settings._automaticDecompression = value;
    }
}

這里的_settings不再是具體的功能類(lèi),而是用于初始化或者保存SocketsHttpHandler的部分屬性值的配置類(lèi)

private readonly HttpConnectionSettings _settings = new HttpConnectionSettings();

這里我們不在分析SocketsHttpHandler出處理響應(yīng)壓縮之外的其他代碼,所以具體就不再看這些了,直接查找_settings._automaticDecompression屬性引用的地方,最終找到了這段代碼

if (settings._automaticDecompression != DecompressionMethods.None)
{
    handler = new DecompressionHandler(settings._automaticDecompression, handler);
}

這里就比較清晰了,真正處理請(qǐng)求響應(yīng)壓縮相關(guān)的都是在DecompressionHandler中。正如我們之前所說(shuō)的,HttpClient真正的工作方式就是一些實(shí)現(xiàn)自HttpMessageHandler的子類(lèi)在工作,它把不同功能的實(shí)現(xiàn)模塊都封裝成了具體的Handler中。當(dāng)你需要使用哪個(gè)模塊的功能,直接使用對(duì)應(yīng)的Handler操作類(lèi)去發(fā)送處理請(qǐng)求即可。這種設(shè)計(jì)思路在ASP.NET Core中體現(xiàn)的也是淋漓盡致,ASP.NET Core采用的是構(gòu)建不同終結(jié)點(diǎn)去處理和輸出請(qǐng)求。通過(guò)這些我們可以得知DecompressionHandler才是今天的主題,接下來(lái)我們就來(lái)查看DecompressionHandler類(lèi)的源碼,我們先來(lái)看最核心的SendAsync方法,這個(gè)方法是發(fā)送請(qǐng)求的執(zhí)行方法

internal override async ValueTask<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
{
    //判斷是否是GZIP壓縮請(qǐng)求,如果是則添加請(qǐng)求頭Accept-Encoding頭為gzip
    if (GZipEnabled && !request.Headers.AcceptEncoding.Contains(s_gzipHeaderValue))
    {
        request.Headers.AcceptEncoding.Add(s_gzipHeaderValue);
    }
    //判斷是否是Deflate壓縮請(qǐng)求,如果是則添加請(qǐng)求頭Accept-Encoding頭為deflate
    if (DeflateEnabled && !request.Headers.AcceptEncoding.Contains(s_deflateHeaderValue))
    {
        request.Headers.AcceptEncoding.Add(s_deflateHeaderValue);
    }
    //判斷是否是Brotli壓縮請(qǐng)求,如果是則添加請(qǐng)求頭Accept-Encoding頭為brotli
    if (BrotliEnabled && !request.Headers.AcceptEncoding.Contains(s_brotliHeaderValue))
    {
        request.Headers.AcceptEncoding.Add(s_brotliHeaderValue);
    }
    //發(fā)送請(qǐng)求
    HttpResponseMessage response = await _innerHandler.SendAsync(request, async, cancellationToken).ConfigureAwait(false);

    Debug.Assert(response.Content != null);
    //獲取返回的Content-Encoding輸出頭信息
    ICollection<string> contentEncodings = response.Content.Headers.ContentEncoding;
    if (contentEncodings.Count > 0)
    {
        string? last = null;
        //獲取最后一個(gè)值
        foreach (string encoding in contentEncodings)
        {
            last = encoding;
        }
        //根據(jù)響應(yīng)頭判斷服務(wù)端采用的是否為gzip壓縮
        if (GZipEnabled && last == Gzip)
        {
            //使用gzip解壓算法解壓返回內(nèi)容,并從新賦值到response.Content
            response.Content = new GZipDecompressedContent(response.Content);
        }
        //根據(jù)響應(yīng)頭判斷服務(wù)端采用的是否為deflate壓縮
        else if (DeflateEnabled && last == Deflate)
        {
            //使用deflate解壓算法解壓返回內(nèi)容,并從新賦值到response.Content
            response.Content = new DeflateDecompressedContent(response.Content);
        }
        //根據(jù)響應(yīng)頭判斷服務(wù)端采用的是否為brotli壓縮
        else if (BrotliEnabled && last == Brotli)
        {
            //使用brotli解壓算法解壓返回內(nèi)容,并從新賦值到response.Content
            response.Content = new BrotliDecompressedContent(response.Content);
        }
    }
    return response;
}

通過(guò)上面的邏輯我們可以看到GZipEnabled、DeflateEnabled、BrotliEnabled三個(gè)bool類(lèi)型的變量,中三個(gè)變量決定了采用哪種請(qǐng)求壓縮方式,主要實(shí)現(xiàn)方式是

internal bool GZipEnabled => (_decompressionMethods & DecompressionMethods.GZip) != 0;
internal bool DeflateEnabled => (_decompressionMethods & DecompressionMethods.Deflate) != 0;
internal bool BrotliEnabled => (_decompressionMethods & DecompressionMethods.Brotli) != 0;

主要就是根據(jù)我們配置的DecompressionMethods枚舉值判斷想獲取哪種方式的壓縮結(jié)果,解壓的實(shí)現(xiàn)邏輯都封裝在GZipDecompressedContent、DeflateDecompressedContentBrotliDecompressedContent中,我們看一下他們的具體的代碼

private sealed class GZipDecompressedContent : DecompressedContent
{
        public GZipDecompressedContent(HttpContent originalContent)
            : base(originalContent)
        { }
        //使用GZipStream類(lèi)對(duì)返回的流進(jìn)行解壓
        protected override Stream GetDecompressedStream(Stream originalStream) =>
            new GZipStream(originalStream, CompressionMode.Decompress);
    }

    private sealed class DeflateDecompressedContent : DecompressedContent
    {
        public DeflateDecompressedContent(HttpContent originalContent)
            : base(originalContent)
        { }
        //使用DeflateStream類(lèi)對(duì)返回的流進(jìn)行解壓
        protected override Stream GetDecompressedStream(Stream originalStream) =>
            new DeflateStream(originalStream, CompressionMode.Decompress);
    }

    private sealed class BrotliDecompressedContent : DecompressedContent
    {
        public BrotliDecompressedContent(HttpContent originalContent) :
            base(originalContent)
        { }
        //使用BrotliStream類(lèi)對(duì)返回的流進(jìn)行解壓
        protected override Stream GetDecompressedStream(Stream originalStream) =>
            new BrotliStream(originalStream, CompressionMode.Decompress);
    }
}

其主要的工作方式就是使用對(duì)應(yīng)壓縮算法的解壓方法得到原始信息。簡(jiǎn)單總結(jié)一下,HttpClient關(guān)于壓縮相關(guān)的處理機(jī)制是,首先根據(jù)你配置的DecompressionMethods判斷你想使用那種壓縮算法。然后匹配到對(duì)應(yīng)的壓縮算法后添加Accept-Encoding請(qǐng)求頭為你期望的壓縮算法。最后根據(jù)響應(yīng)結(jié)果獲取Content-Encoding輸出頭信息,判斷服務(wù)端采用的是哪種壓縮算法,并采用對(duì)應(yīng)的解壓方法解壓獲取原始數(shù)據(jù)。

總結(jié):

    通過(guò)本次探討HttpClient關(guān)于響應(yīng)壓縮的處理我們可以了解到,HttpClient無(wú)論從設(shè)計(jì)上還是實(shí)現(xiàn)方式上都有非常高的靈活性和擴(kuò)展性,這也是為什么到了.Net Core上官方只推薦使用HttpClient一種Http請(qǐng)求方式。由于使用比較簡(jiǎn)單,實(shí)現(xiàn)方式比較清晰,這里就不過(guò)多拗述。主要是是想告訴大家HttpClient默認(rèn)可以直接處理響應(yīng)壓縮,而不是和之前我們使用HttpWebRequest的時(shí)候還需要手動(dòng)編碼的方式去實(shí)現(xiàn)。

相關(guān)文章

  • asp.net創(chuàng)建事務(wù)的方法

    asp.net創(chuàng)建事務(wù)的方法

    本篇文章主要對(duì)asp.net創(chuàng)建事務(wù)的方法進(jìn)行實(shí)例介紹,具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧
    2016-12-12
  • DataGridView控件詳細(xì)介紹

    DataGridView控件詳細(xì)介紹

    DataGridView是用于Windows Froms 2.0的新網(wǎng)格控件。它可以取代先前版本中DataGrid控件,它易于使用并高度可定制,支持很多我們的用戶(hù)需要的特性
    2012-11-11
  • ASP.NET Core 中間件的使用之全局異常處理機(jī)制

    ASP.NET Core 中間件的使用之全局異常處理機(jī)制

    我們今天這篇文章就來(lái)說(shuō)說(shuō)代碼異常問(wèn)題怎么快速定位,減少不必要的時(shí)間浪費(fèi)。異常是一種運(yùn)行時(shí)錯(cuò)誤,當(dāng)異常沒(méi)有得到適當(dāng)?shù)奶幚?,很可能?huì)導(dǎo)致你的程序意外終止。下面雄安邊將詳細(xì)介紹,需要的朋友可以參考下
    2021-09-09
  • ASP.NET?Core使用功能開(kāi)關(guān)控制路由訪(fǎng)問(wèn)操作(續(xù))

    ASP.NET?Core使用功能開(kāi)關(guān)控制路由訪(fǎng)問(wèn)操作(續(xù))

    這篇文章主要介紹了ASP.NET?Core使用功能開(kāi)關(guān)控制路由訪(fǎng)問(wèn)操作的(續(xù)),上一篇文章我們已經(jīng)介紹過(guò)一部份該相關(guān)內(nèi)容,??在本文,我們可以判斷當(dāng)前路由地址是否為調(diào)試地址,讓評(píng)估返回真,需要的小伙伴可以參考一下
    2022-02-02
  • Net內(nèi)存管理五大基礎(chǔ)

    Net內(nèi)存管理五大基礎(chǔ)

    這篇文章主要給大家分享Net內(nèi)存管理五大基礎(chǔ)內(nèi)容,文章講圍繞Net內(nèi)存管理詳細(xì)介紹文章內(nèi)容,感興趣的朋友可以參考一下,希望對(duì)你有所幫助
    2021-10-10
  • 在NET?Core?中獲取?CPU?使用率

    在NET?Core?中獲取?CPU?使用率

    這篇文章我們分享一種如何在?.NETCore?中獲取?CPU使用率的方法,?它所報(bào)告的這個(gè)值和?任務(wù)管理器?中報(bào)告的?CPU?使用值?差不多是一致的,下面來(lái)看看文中的具體詳細(xì)介紹吧
    2022-01-01
  • ASP遺留的二十個(gè)積習(xí)

    ASP遺留的二十個(gè)積習(xí)

    ASP遺留的二十個(gè)積習(xí)
    2006-07-07
  • 設(shè)計(jì)windows phone頁(yè)面主題

    設(shè)計(jì)windows phone頁(yè)面主題

    這篇文章主要介紹了設(shè)計(jì)windows phone頁(yè)面主題,需要的朋友可以參考下
    2015-07-07
  • .net程序開(kāi)發(fā)IOC控制反轉(zhuǎn)和DI依賴(lài)注入詳解

    .net程序開(kāi)發(fā)IOC控制反轉(zhuǎn)和DI依賴(lài)注入詳解

    這篇文章主要為大家介紹了.net程序開(kāi)發(fā)IOC控制反轉(zhuǎn)和DI依賴(lài)注入示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • .Net執(zhí)行SQL存儲(chǔ)過(guò)程之易用輕量工具詳解

    .Net執(zhí)行SQL存儲(chǔ)過(guò)程之易用輕量工具詳解

    這篇文章主要為大家介紹了.Net執(zhí)行SQL存儲(chǔ)過(guò)程之易用輕量工具詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評(píng)論