日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

.net core HttpClient 使用之掉坑解析(一)

發布時間:2023/12/4 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .net core HttpClient 使用之掉坑解析(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

在我們開發當中經常需要向特定URL地址發送Http請求操作,在.net core 中對httpClient使用不當會造成災難性的問題,這篇文章主要來分享.net core中通過IHttpClientFactory 工廠來使用HttpClient的正確打開方式。

二、HttpClient使用中的那些坑

2.1 錯誤使用

using(var client = new HttpClient())

我們可以先來做一個簡單的測試,代碼如下:

public async Task<string> GetBaiduListAsync(string url){var html = "";for (var i = 0; i < 10; i++){using (var client = new System.Net.Http.HttpClient()){var result=await client.GetStringAsync(url);html += result;}}return html;}

運行項目輸出結果后,通過netstate查看下TCP連接情況:雖然項目已經運行結束,但是連接依然存在,狀態為" TIME_WAIT"(繼續等待看是否還有延遲的包會傳輸過來;默認在windows下,TIME_WAIT狀態將會使系統將會保持該連接 240s。在高并發的情況下,連接來不及釋放,socket被耗盡,耗盡之后就會出現喜聞樂見的一個錯誤:

錯誤原因:

對象所占用資源應該確保及時被釋放掉,但是,對于網絡連接而言,這是錯誤的,原因有如下:

  • 網絡連接是需要耗費一定時間的,頻繁開啟與關閉連接,性能會受影響;

  • 開啟網絡連接時會占用底層socket資源,但在HttpClient調用其本身的Dispose方法時,并不能立刻釋放該資源,這意味著你的程序可能會因為耗盡連接資源而產生災難性的問題。

對于上面的錯誤原因,大家可能會想到使用靜態單例模式的HttpClient,如下:

private static HttpClient Client = new HttpClient();

靜態單例模式雖然可以解決上面問題,但是會帶來另外一個問題:

  • DNS變更會導致不能解析,DNS不會重新加載,需要重啟才能變更(有興趣的大佬可以去嘗試一下)

三、正確使用及源碼分析

HttpClientFactory 以模塊化、可命名、可配置、彈性方式重建了 HttpClient 的使用方式:由 DI 框架注入 IHttpClientFactory 工廠;由工廠創建 HttpClient 并從內部的 Handler 池分配請求 Handler。

.net core 2.1 開始引入了IHttpClientFactory 工廠類來自動管理IHttpClientFactory 類的創建和資源釋放,可以通過Ioc 注入方式進行使用,代碼如下:

services.AddControllers(); services.AddHttpClient();

調用代碼如下:

private readonly IHttpClientFactory _clientFactory;public FirstController(IHttpClientFactory clientFactory) {_clientFactory = clientFactory; }/// <summary> /// /// </summary> /// <param name="url"></param> /// <returns></returns> public async Task<string> GetBaiduAsync(string url) {var client = _clientFactory.CreateClient();var result = await client.GetStringAsync(url);return result; }

代碼中通過IHttpClientFactory 中的CreateClient()方法進行創建一個HttpClient 對象,但是沒有看到有釋放資源的動作,那它是怎么釋放的呢?我們來看看它的主要源代碼

/// <summary> /// Creates a new <see cref="HttpClient"/> using the default configuration. /// </summary> /// <param name="factory">The <see cref="IHttpClientFactory"/>.</param> /// <returns>An <see cref="HttpClient"/> configured using the default configuration.</returns> public static HttpClient CreateClient(this IHttpClientFactory factory) {if (factory == null){throw new ArgumentNullException(nameof(factory));}return factory.CreateClient(Options.DefaultName); }public HttpClient CreateClient(string name) {if (name == null){throw new ArgumentNullException(nameof(name));}var handler = CreateHandler(name);var client = new HttpClient(handler, disposeHandler: false);var options = _optionsMonitor.Get(name);for (var i = 0; i < options.HttpClientActions.Count; i++){options.HttpClientActions[i](client);}return client; }public HttpMessageHandler CreateHandler(string name) {if (name == null){throw new ArgumentNullException(nameof(name));}var entry = _activeHandlers.GetOrAdd(name, _entryFactory).Value;StartHandlerEntryTimer(entry);return entry.Handler; }

代碼中可以看到創建HttpClent 時會先創建HttpMessageHandler對象,而CreateHandler 方法中調用了StartHandlerEntryTimer方法,該方法主要時啟動清理釋放定時器方法,核心代碼如下:

public DefaultHttpClientFactory(IServiceProvider services,IServiceScopeFactory scopeFactory,ILoggerFactory loggerFactory,IOptionsMonitor<HttpClientFactoryOptions> optionsMonitor,IEnumerable<IHttpMessageHandlerBuilderFilter> filters){if (services == null){throw new ArgumentNullException(nameof(services));}if (scopeFactory == null){throw new ArgumentNullException(nameof(scopeFactory));}if (loggerFactory == null){throw new ArgumentNullException(nameof(loggerFactory));}if (optionsMonitor == null){throw new ArgumentNullException(nameof(optionsMonitor));}if (filters == null){throw new ArgumentNullException(nameof(filters));}_services = services;_scopeFactory = scopeFactory;_optionsMonitor = optionsMonitor;_filters = filters.ToArray();_logger = loggerFactory.CreateLogger<DefaultHttpClientFactory>();// case-sensitive because named options is._activeHandlers = new ConcurrentDictionary<string, Lazy<ActiveHandlerTrackingEntry>>(StringComparer.Ordinal);_entryFactory = (name) =>{return new Lazy<ActiveHandlerTrackingEntry>(() =>{return CreateHandlerEntry(name);}, LazyThreadSafetyMode.ExecutionAndPublication);};_expiredHandlers = new ConcurrentQueue<ExpiredHandlerTrackingEntry>();_expiryCallback = ExpiryTimer_Tick;_cleanupTimerLock = new object();_cleanupActiveLock = new object();}// Internal for testsinternal void ExpiryTimer_Tick(object state){var active = (ActiveHandlerTrackingEntry)state;// The timer callback should be the only one removing from the active collection. If we can't find// our entry in the collection, then this is a bug.var removed = _activeHandlers.TryRemove(active.Name, out var found);Debug.Assert(removed, "Entry not found. We should always be able to remove the entry");Debug.Assert(object.ReferenceEquals(active, found.Value), "Different entry found. The entry should not have been replaced");// At this point the handler is no longer 'active' and will not be handed out to any new clients.// However we haven't dropped our strong reference to the handler, so we can't yet determine if// there are still any other outstanding references (we know there is at least one).//// We use a different state object to track expired handlers. This allows any other thread that acquired// the 'active' entry to use it without safety problems.var expired = new ExpiredHandlerTrackingEntry(active);_expiredHandlers.Enqueue(expired);Log.HandlerExpired(_logger, active.Name, active.Lifetime);StartCleanupTimer();}// Internal so it can be overridden in testsinternal virtual void StartHandlerEntryTimer(ActiveHandlerTrackingEntry entry){entry.StartExpiryTimer(_expiryCallback);}

從微軟源碼分析,HttpClient繼承自HttpMessageInvoker,而HttpMessageInvoker實質就是HttpClientHandler。

HttpClientFactory 創建的HttpClient,也即是HttpClientHandler,只是這些個HttpClient被放到了“池子”中,工廠每次在create的時候會自動判斷是新建還是復用。(默認生命周期為2min)。希望這篇文章對你有幫助,如果對你有幫助請點個推薦,感謝!

往期精彩回顧



  • 【.net core】電商平臺升級之微服務架構應用實戰

  • .Net Core微服務架構技術棧的那些事

  • .net core 基于Dapper 的分庫分表開源框架(core-data)

  • Asp.Net Core 中IdentityServer4 授權中心之應用實戰

  • Asp.Net Core 中IdentityServer4 授權中心之自定義授權模式

  • Asp.Net Core 中IdentityServer4 授權流程及刷新Token

  • Asp.Net Core 中IdentityServer4 實戰之 Claim詳解

  • Asp.Net Core 中IdentityServer4 實戰之角色授權詳解

  • Asp.Net Core 中間件應用實戰中你不知道的那些事

  • Asp.Net Core Filter 深入淺出的那些事-AOP

  • Asp.Net Core EndPoint 終結點路由工作原理解讀

  • ASP.NET CORE 內置的IOC解讀及使用


總結

以上是生活随笔為你收集整理的.net core HttpClient 使用之掉坑解析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。