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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

HttpClientFactory的套路,你知多少?

發布時間:2023/12/4 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HttpClientFactory的套路,你知多少? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

ASP.NET Core 在 2.1 之后推出了具有彈性 HTTP 請求能力的 HttpClient 工廠類 HttpClientFactory。

替換的初衷還是簡單擺一下:
① using(var client = new HttpClient()) 調用的 Dispose() 方法并不會立即釋放底層 Socket 連接,新建 Socket 需要時間,導致在高并發場景下 Socket 耗盡。
② 基于 ① 很多人會想到使用單例或者靜態類構造 HttpClient 實例,但是這里有一個坑,HttpClient 不會反應 DNS 的變更。

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

HttpClient 可在 DI 框架中通過IHttpCLientBuilder對象配置 Policy 策略。

我一直對這種顛覆傳統 HttpClient 的代碼組織方式感到好奇,今天我們帶著問題來探究一下新版 HttpClient 的實現。

與碼無瓜

一個完整的 HttpClient 包括三部分:

  • 基礎業務配置:BaseAddress、DefaultRequestHeaders、DefaultProxy、TimeOut.....

  • 核心 MessageHandler:負責核心的業務請求

  • [可選的]附加 HttpMessageHandler

附加的 HttpMessageHandler 需要與核心 HttpMessageHandler 形成鏈式 Pipeline 關系,最終端點指向核心 HttpMessageHandler,
鏈表數據結構是 DelegatingHandler 關鍵類(包含 InnerHandler 鏈表節點指針)

刨瓜問底

很明顯,HttpClientFactory 源碼的解讀分為 2 部分,心里藏著偽代碼,帶著問題思考更香(手動狗頭)。

P1. 構建 HttpClient

在 Startup.cs 文件開始配置要用到的 HttpClient

services.AddHttpClient("bce-request", x =>x.BaseAddress = new Uri(Configuration.GetSection("BCE").GetValue<string>("BaseUrl"))).ConfigurePrimaryHttpMessageHandler(_ => new BceAuthClientHandler(){AccessKey = Configuration.GetSection("BCE").GetValue<string>("AccessKey"),SerectAccessKey = Configuration.GetSection("BCE").GetValue<string>("SecretAccessKey"),AllowAutoRedirect = true,UseDefaultCredentials = true}).SetHandlerLifetime(TimeSpan.FromHours(12)).AddPolicyHandler(GetRetryPolicy(3));

配置過程充分體現了.NET Core 推崇的萬物皆服務,配置前移的 DI 風格;
同對時 HttpClient 的基礎、配置均通過配置即委托來完成

Q1. 如何記錄以上配置?

微軟使用一個HttpClientFactoryOptions對象來記錄 HttpClient 配置,這個套路是不是很熟悉?

  • 通過 DI 框架的AddHttpClient擴展方法產生 HttpClientBuilder 對象

  • HttpClientBuilder 對象的ConfigurePrimaryHttpMessageHandler擴展方法會將核心 Handler 插到 Options 對象的 HttpMessageHandlerBuilderActions 數組,作為 Handlers 數組中的 PrimaryHandler

  • HttpClientBuilder 對象的AddPolicyHandler擴展方法也會將 PolicyHttpMessageHandler 插到 Options 對象的 HttpMessageHandlerBuilderActions 數組,但是作為 AdditionHandler

// An options class for configuring the default System.Net.Http.IHttpClientFactorypublic class HttpClientFactoryOptions{public HttpClientFactoryOptions();// 一組用于配置HttpMessageHandlerBuilder的操作委托public IList<Action<HttpMessageHandlerBuilder>> HttpMessageHandlerBuilderActions { get; }public IList<Action<HttpClient>> HttpClientActions { get; }public TimeSpan HandlerLifetime { get; set; }public bool SuppressHandlerScope { get; set; }}

顯而易見,后期創建 HttpClient 實例時會通過 name 找到對應的 Options,從中加載配置和 Handlers。

P2. 初始化 HttpClient 實例

通過 IHttpClientFactory.CreateClient() 產生的 HttpClient 實例有一些內部行為:
標準的 HttpClient(不帶 Policy 策略)除了 PrimaryHandler 之外,微軟給你附加了兩個 AdditionHandler:

  • LoggingScopeHttpMessageHandler:最外圍 Logical 日志

  • LoggingHttpMessageHandler:核心 Http 請求日志

之后將排序后的 AdditionHanders 數組與 PrimaryHandler 通過 DelegatingHandler 數據結構轉化為鏈表, 末節點是 PrimaryHandler

輸出的日志如下:

Q2. 微軟為啥要增加外圍日志 Handler?

這要結合 P1 給出的帶 Policy 策略的 HttpClient,帶 Policy 策略的 HttpClient 會在 AdditionHandlers 插入 PolicyHttpMessageHandler 來控制retry、Circuit Breaker,那么就會構建這樣的 Handler Pipeline:

所以微軟會在 AdditionHandlers 數組最外圍提供一個業務含義的日志 LogicalHandler,最內層固定 LoggingHttpHandler,這是不是很靠譜?

無圖無真相,請查看帶Policy策略的 HttpClient 請求堆棧:

Q3. 何處強插、強行固定這兩個日志 Handler?
微軟通過在 DI 環節注入默認的 LoggingHttpMessageHandlerBuilderFilter 來重排 Handler 的位置:

// 截取自LoggingHttpMessageHandlerBuilderFilter文件 public Action<HttpMessageHandlerBuilder> Configure(Action<HttpMessageHandlerBuilder> next) {return (builder) =>{next(builder);var loggerName = !string.IsNullOrEmpty(builder.Name) ? builder.Name : "Default";// We want all of our logging message to show up as-if they are coming from HttpClient,// but also to include the name of the client for more fine-grained control.var outerLogger = _loggerFactory.CreateLogger($"System.Net.Http.HttpClient.{loggerName}.LogicalHandler");var innerLogger = _loggerFactory.CreateLogger($"System.Net.Http.HttpClient.{loggerName}.ClientHandler");var options = _optionsMonitor.Get(builder.Name);// The 'scope' handler goes first so it can surround everything.builder.AdditionalHandlers.Insert(0, new LoggingScopeHttpMessageHandler(outerLogger, options));// We want this handler to be last so we can log details about the request after// service discovery and security happen.builder.AdditionalHandlers.Add(new LoggingHttpMessageHandler(innerLogger, options));}; }

Q4. 創建 HttpClient 時,如何將 AdditionHandlers 和 PrimaryHandler 形成鏈式 Pipeline 關系 ?

protected internal static HttpMessageHandler CreateHandlerPipeline(HttpMessageHandler primaryHandler, IEnumerable<DelegatingHandler> additionalHandlers) {var additionalHandlersList = additionalHandlers as IReadOnlyList<DelegatingHandler> ?? additionalHandlers.ToArray();var next = primaryHandler;for (var i = additionalHandlersList.Count - 1; i >= 0; i--){var handler = additionalHandlersList[i];if (handler == null){var message = Resources.FormatHttpMessageHandlerBuilder_AdditionalHandlerIsNull(nameof(additionalHandlers));throw new InvalidOperationException(message);}handler.InnerHandler = next;next = handler;} }

數組轉鏈表IReadOnlyList<DelegatingHandler>的算法與 ASP.NET Core 框架的 Middleware 構建 Pipeline 如出一轍。

總結

偽代碼演示實例創建過程:
DefaultHttpClientFactory.CreateClient()
--->構造函數由 DI 注入默認的 LoggingHttpMessageHandlerBuilderFilter
--->通過 Options.HttpMessageHandlerBuilderActions 拿到所有的 Handlers
--->使用 LoggingHttpMessageHandlerBuilderFilter 強排 AdditionHandlers
--->創建 Handler 鏈式管道
--->用以上鏈式初始化 HttpClient 實例
--->從 Options.HttpClientActions 中提取對于 Httpclient 的基礎配置
--->返回一個基礎、HttpHandler 均正確配置的 HttpClient 實例

上述行為依賴于 ASP.NETCor 框架在 DI 階段注入的幾個服務:

  • DefaultHttpClientFactory

  • LoggingHttpMessageHandlerBuilderFilter:過濾并強排 AdditionHandlers

  • DefaultHttpMessageHandlerBuilder:Handler數組轉鏈表

我們探究System.Net.Http庫的目的:
學習精良的設計模式、理解默認的DI行為;
默認DI行為給我們提供了擴展/改造 HttpClientFactory 的一個思路:HttpClientFactory日志不好用,自己擴展一個?

  • https://github.com/dotnet/extensions/blob/master/src/HttpClientFactory/Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs

  • https://github.com/dotnet/extensions/blob/master/src/HttpClientFactory/Http/src/DefaultHttpClientFactory.cs

推薦閱讀

●?程序員應對瀏覽器同源策略的姿勢

●?臨近年關,修復ASP.NET Core因瀏覽器內核版本引發的單點登錄故障

●?ASP.NET Core跨平臺技術內幕

●?TPL Dataflow組件應對高并發,低延遲要求

●?實例解讀Docker Swarm

●?基于docker-compose的Gitlab CI/CD實踐&排坑指南

總結

以上是生活随笔為你收集整理的HttpClientFactory的套路,你知多少?的全部內容,希望文章能夠幫你解決所遇到的問題。

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