.NET Core 2.1中HttpClientFactory的最佳實(shí)踐記錄
前言
ASP.NET Core 2.1中出現(xiàn)一個(gè)新的HttpClientFactory功能,
它有助于解決開(kāi)發(fā)人員在使用HttpClient實(shí)例從其應(yīng)用程序發(fā)出外部Web請(qǐng)求時(shí)可能遇到的一些常見(jiàn)問(wèn)題。
介紹
在.NETCore平臺(tái)的2.1新增了HttpClientFactory,雖然HttpClient這個(gè)類(lèi)實(shí)現(xiàn)了disposable,但使用它的時(shí)候用聲明using包裝塊的方式通常不是最好的選擇。處理HttpClient,底層socket套接字不會(huì)立即釋放。該HttpClient類(lèi)是專(zhuān)為多個(gè)請(qǐng)求重復(fù)使用而創(chuàng)建的。需要不同的基地址,不同的HTTP標(biāo)頭和其他對(duì)請(qǐng)求個(gè)性化操作的場(chǎng)景時(shí),需要手動(dòng)管理多個(gè)HttpClient實(shí)例,為了簡(jiǎn)化HttpClient實(shí)例管理,.NET Core 2.1提供了一個(gè)新的HTTPClientFactory - 它可以創(chuàng)建,緩存和處理HttpClient實(shí)例。
什么是HttpClientFactory?
用ASP.NET團(tuán)隊(duì)的話說(shuō):“an opinionated factory for creating HttpClient instances”(一個(gè)用于創(chuàng)建HttpClient實(shí)例的最佳實(shí)踐的工廠),并且是ASP.NET Core 2.1發(fā)布的新功能。根據(jù)大家以前使用HttpClient的經(jīng)驗(yàn),您可能遇到一些困擾的問(wèn)題,有時(shí)甚至沒(méi)有意識(shí)到您有問(wèn)題(只是在并發(fā)并不大的場(chǎng)景沒(méi)觸發(fā)而已)。
第一個(gè)問(wèn)題是當(dāng)你在代碼中創(chuàng)建太多的HttpClients時(shí),這反過(guò)來(lái)會(huì)產(chǎn)生兩個(gè)問(wèn)題......
- 這是低效的,因?yàn)槊總€(gè)請(qǐng)求都有自己的遠(yuǎn)程服務(wù)器連接池。這意味著您需要為每個(gè)創(chuàng)建的客戶(hù)端支付重新連接到該遠(yuǎn)程服務(wù)器的成本。
- 更大的問(wèn)題是如果你創(chuàng)建了很多HttpClient并使用到他們,你可以遇到Socket耗盡,而你基本上已經(jīng)太快地使用了過(guò)多的Socket。您可以同時(shí)打開(kāi)多個(gè)Socket是有限制的。當(dāng)您dispose銷(xiāo)毀HttpClient時(shí),它打開(kāi)的連接在TIME_WAIT狀態(tài)下保持打開(kāi)狀態(tài)最長(zhǎng)240秒(如果來(lái)自遠(yuǎn)程服務(wù)器的任何數(shù)據(jù)包仍然通過(guò))。
HttpClient實(shí)現(xiàn)了IDisposable,這通常會(huì)導(dǎo)致開(kāi)發(fā)人員在使用IDisposable對(duì)象時(shí)遵循正常模式,在using塊中創(chuàng)建它。這樣可以確保一旦完成對(duì)象并且它已經(jīng)超出范圍,就可以正確銷(xiāo)毀對(duì)象。
因此,最優(yōu)的方法是重用HttpClient實(shí)例,以便也可以重用連接。HttpClient是一個(gè)可變對(duì)象,但只要你沒(méi)有運(yùn)行期改變它,它實(shí)際上是線程安全的并且可以共享。因此,一種常見(jiàn)的方法是將其注冊(cè)為具有DI框架的單例模式,或者創(chuàng)建包含static靜態(tài)實(shí)例的對(duì)象。
但是,這會(huì)產(chǎn)生新問(wèn)題。以這種方式使用單個(gè)HttpClient將保持連接打開(kāi)并且不遵守DNS生存時(shí)間(TTL)設(shè)置(總之就是同一個(gè)HttpClient實(shí)例只能有一個(gè)請(qǐng)求頭,在被請(qǐng)求方發(fā)生更改時(shí),由于是單例不能做個(gè)性化改變,否則導(dǎo)致其他請(qǐng)求失敗)?,F(xiàn)在連接將永遠(yuǎn)不會(huì)獲得DNS更新,因此您正在與之通信的服務(wù)器將永遠(yuǎn)不會(huì)更新其地址。在某些情況下,這是完全有可能的,在以上這種情況下,您可以平衡許多主機(jī),這些主機(jī)可能隨著時(shí)間的推移而改變,或者可能使用Blue/Green 部署推出新服務(wù)。如果服務(wù)器消改變,則您的連接使用的IP可能不再響應(yīng)您通過(guò)單個(gè)HttpClient發(fā)出的請(qǐng)求。
所以需要我們手動(dòng)去管理每類(lèi)服務(wù)器的HttpClient的實(shí)例來(lái)進(jìn)行個(gè)性化請(qǐng)求頭的構(gòu)造和發(fā)起請(qǐng)求!
HttpClientFactory旨在幫助您開(kāi)始解決這些問(wèn)題,并提供了一種新的機(jī)制來(lái)創(chuàng)建在幕后為我們正確管理的HttpClient實(shí)例。它將為我們“做管理HttpClient的事”,我們可以專(zhuān)注于業(yè)務(wù)!雖然在參考HttpClient時(shí)提到了上述問(wèn)題,但事實(shí)上問(wèn)題的根源實(shí)際上發(fā)生在HttpClient上,HttpClient使用了HttpClientHandler。HttpClientFactory管理處理程序的生命周期,以便我們有一個(gè)可以重用的池,同時(shí)還可以(Rotating)輪換它們以使DNS不會(huì)過(guò)時(shí)。
使用HttpClient的昂貴部分實(shí)際上是創(chuàng)建HttpClientHandler和連接。以這種HttpClientFacotry方式匯集這些內(nèi)容意味著我們可以更高效利用資源最節(jié)省地使用我們系統(tǒng)上的socket。當(dāng)您使用HttpClientFactory請(qǐng)求HttpClient時(shí),實(shí)際上每次都會(huì)獲得一個(gè)新實(shí)例,這意味著我們不必?fù)?dān)心會(huì)改變它的狀態(tài)。此HttpClient可能(或可能不)使用池中的現(xiàn)有HttpClientHandler,從而使用現(xiàn)有打開(kāi)的連接。
默認(rèn)情況下,每個(gè)新創(chuàng)建的HttpClientHandler(派生自HttpMessageHandler)生命周期只有2分鐘。通過(guò)services.AddHttpClient()創(chuàng)建HttpClientFactory實(shí)例時(shí),可以根據(jù)每一個(gè)命名的Client客戶(hù)機(jī)進(jìn)行控制。達(dá)到生命周期后,處理程序?qū)⒉粫?huì)立即被釋放掉,而是放入過(guò)期的池中。任何依賴(lài)于HttpClientFactory的處理程序鏈的客戶(hù)端都可以繼續(xù)使用它而沒(méi)有任何問(wèn)題。有一個(gè)后臺(tái)作業(yè)檢查過(guò)期的池,以查看處理程序的所有引用是否已在scope之外,此時(shí)可以將其釋放掉。處理程序鏈過(guò)期后對(duì)新客戶(hù)端的任何新請(qǐng)求都將獲得新的處理程序鏈。
這種方法運(yùn)行得相當(dāng)不錯(cuò),但.NET Core方面還有其他一些事情可能會(huì)進(jìn)一步改善這種情況。.NET Core團(tuán)隊(duì)開(kāi)發(fā)了一個(gè)新的ManagedHandler,它可以更正確地管理DNS,原則上可以保持更長(zhǎng)時(shí)間,這意味著可以更有效地共享連接。這個(gè)新的處理程序還被設(shè)計(jì)為在不同的操作系統(tǒng)中更加一致地運(yùn)行。在該工作完成之前,上面的處理程序池是一個(gè)合理的解決方法。
如何使用HttpClientFactory
我們將首先創(chuàng)建一個(gè)簡(jiǎn)單的WebAPI項(xiàng)目
接下來(lái),我們需要轉(zhuǎn)到我們的Startup.cs文件并注冊(cè)一個(gè)服務(wù)。
services.AddHttpClient(); services.AddScoped(typeof(ClassInService));//此處無(wú)關(guān)HttpClient,請(qǐng)暫時(shí)忽視他
在幕后,這將注冊(cè)一些必需的服務(wù),其中一個(gè)是IHttpClientFactory的實(shí)現(xiàn)。接下來(lái),我們?cè)跇I(yè)務(wù)中使用他
public class ClassInService { /// <summary> /// 構(gòu)建器 /// </summary> /// <param name="clientFactory"></param> public ClassInService(IHttpClientFactory clientFactory) { _clientFactory = clientFactory; } }
private void HttpClientFactoryTest() { var client = _clientFactory.CreateClient("這是專(zhuān)門(mén)用來(lái)連接博客園的");//必須和services.AddHttpClient()中指定的名稱(chēng)對(duì)應(yīng) var content = new StringContent($"SID={SID}&safeKey={111}"); content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); var response = client.PostAsync("MyBlogUrl", content); }
這里我們首先添加對(duì)IHttpClientFactory的依賴(lài),它將由DI系統(tǒng)注入ClassInService。IHttpClientFactory允許我們請(qǐng)求和接收HttpClient實(shí)例。
我們使用HttpClientFactory創(chuàng)建客戶(hù)端。在幕后,HttpClientFactory將為我們創(chuàng)建一個(gè)新的HttpClient。但是等等,之前說(shuō)過(guò)為每個(gè)請(qǐng)求使用新的HttpClient是很糟糕。但此處的創(chuàng)建的httpclient是在他所管理的池子中,并不每個(gè)請(qǐng)求都會(huì)是新的socket。
HttpClientFactory收集這些HttpClientHandler實(shí)例并管理它們的生命周期,以解決之前提到的一些問(wèn)題。每次我們要求HttpClient時(shí),我們都會(huì)得到一個(gè)新實(shí)例,它可能(或可能不)使用現(xiàn)有的HttpClientHandler。HttpClient本身并沒(méi)有問(wèn)題。
一旦創(chuàng)建,由此創(chuàng)建的所有HttpClientHandler將被默認(rèn)保持約2分鐘。這意味著針對(duì)同一個(gè)CreateClient的任何新請(qǐng)求都可以共享處理程序,因此也可以共享連接。當(dāng)HttpClient存在時(shí),它的處理程序?qū)⒈3挚捎脿顟B(tài),并且它將再次共享連接。
兩分鐘后,每個(gè)HttpClientHandler都標(biāo)記為已過(guò)期。過(guò)期狀態(tài)只是標(biāo)記它們,以便在創(chuàng)建任何新的HttpClient實(shí)例時(shí)不再使用它們。但是,它們不會(huì)立即銷(xiāo)毀,因?yàn)槠渌鸋ttpClient實(shí)例可能正在使用它們。HttpClientFactory使用后臺(tái)服務(wù)監(jiān)視過(guò)期的處理程序,一旦它們不再被引用,就可以正確釋放它們,也允許它們的連接被關(guān)閉。
概要
通過(guò)使用HttpClientfactory我們不需要考慮如何管理HttpClient的生命周期或擔(dān)心遇到DNS問(wèn)題。以上只是HttpClient小小的最佳使用推薦,還有其他高級(jí)用法,例如和Polly的結(jié)合使用。
參考:https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- asp.net core為IHttpClientFactory添加動(dòng)態(tài)命名配置
- 如何在ASP.NET Core中使用HttpClientFactory
- 詳解如何在ASP.NET Core中使用IHttpClientFactory
- .net Core 使用IHttpClientFactory請(qǐng)求實(shí)現(xiàn)
- .Net Core下HTTP請(qǐng)求IHttpClientFactory示例詳解
- DotNetCore深入了解之HttpClientFactory類(lèi)詳解
- 如何利用HttpClientFactory實(shí)現(xiàn)簡(jiǎn)單的熔斷降級(jí)
- .NET Core中的HttpClientFactory類(lèi)用法詳解
相關(guān)文章
ASP.NET Internet安全Forms身份驗(yàn)證方法
安全性是 ASP.NET Web 應(yīng)用程序中一個(gè)非常重要的方面,它涉及內(nèi)容非常廣泛,不能在一篇文章內(nèi)說(shuō)明所有的安全規(guī)范,本文講述如何利用IIS以及Forms 身份驗(yàn)證構(gòu)建安全的 ASP.NET 應(yīng)用程序,它是目前被使用最多最廣的驗(yàn)證/授權(quán)方式.2009-12-12基于.NET程序默認(rèn)啟動(dòng)線程數(shù)講解
本篇文章小編為大家介紹,基于.NET程序默認(rèn)啟動(dòng)線程數(shù)講解。需要的朋友參考下2013-04-04ASP.NET使用My97DatePicker日期控件實(shí)例
這篇文章主要為大家詳細(xì)介紹了ASP.NET使用My97DatePicker日期控件實(shí)例,如何使用My97DatePicker日期控件,本文為大家介紹,感興趣的小伙伴們可以參考一下2016-04-04asp.net類(lèi)序列化生成xml文件實(shí)例詳解
這篇文章主要介紹了asp.net類(lèi)序列化生成xml文件的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了asp.net序列化生成xml文件的具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-11-11自己常用到的自定義公共類(lèi)(已測(cè)試通過(guò))
自己常用到的自定義公共類(lèi)(已測(cè)試通過(guò))...2007-03-03asp.net 仿騰訊微薄提示 還能輸入*個(gè)字符 的實(shí)現(xiàn)代碼
asp.net 仿騰訊微薄提示 還能輸入*個(gè)字符 的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2011-10-10