diff --git a/HttpClientStudy.Core/PipelineClient.cs b/HttpClientStudy.Core/PipelineClient.cs
new file mode 100644
index 0000000..007ff05
--- /dev/null
+++ b/HttpClientStudy.Core/PipelineClient.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HttpClientStudy.Core
+{
+ ///
+ /// 管道方式 HttpClient客户端
+ ///
+ public class PipelineClient
+ {
+ public List HttpMessageHandlers { get; set; }
+
+ public PipelineClient()
+ {
+ HttpMessageHandlers = new List()
+ {
+ new CustomHeadersHandler(),
+ new LoggingHandler(),
+ };
+
+ }
+
+ public PipelineClient(List httpMessageHandlers)
+ {
+ HttpMessageHandlers = httpMessageHandlers;
+ if (httpMessageHandlers == null || httpMessageHandlers?.Count == 0)
+ {
+ HttpMessageHandlers = new List();
+ }
+ }
+
+ public void AddDelegatingHandler(DelegatingHandler handler)
+ {
+ this.HttpMessageHandlers.Add(handler);
+ }
+
+ public HttpClient CreateHttpClient()
+ {
+ //创建处理器链
+
+ //最终处理器:最后一个请求处理程序,默认是SocketsHttpHandler.
+ HttpMessageHandler currentPipeLine = new SocketsHttpHandler()
+ {
+ //自定义配置
+ PooledConnectionLifetime = TimeSpan.FromSeconds(120),
+ };
+ //pipeline = new CustomHeadersHandler() { InnerHandler = pipeline};
+ //pipeline = new LoggingHandler () { InnerHandler = pipeline};
+
+ //倒序组装:完成后执行顺序与注册顺序一致
+ HttpMessageHandlers.Reverse();
+ for (int i = 0; i < HttpMessageHandlers.Count; i++)
+ {
+ HttpMessageHandlers[i].InnerHandler = currentPipeLine;
+ currentPipeLine = HttpMessageHandlers[i];
+ }
+
+ // 利用管道创建HttpClient
+ var httpClient = new HttpClient(currentPipeLine);
+
+ return httpClient;
+ }
+ }
+
+ ///
+ /// 默认处理器1 - 添加自定义请求头
+ ///
+ public class CustomHeadersHandler : DelegatingHandler
+ {
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ // 在请求中添加自定义头部
+ request.Headers.Add("X-Custom-Header", "CustomValue");
+
+ // 调用管道中的下一个处理器
+ return await base.SendAsync(request, cancellationToken);
+
+ //响应信息(可不处理)
+ }
+ }
+
+ ///
+ /// 默认处理器1 - 简单的日志记录
+ ///
+ public class LoggingHandler : DelegatingHandler
+ {
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ // 记录请求信息
+ Console.WriteLine($"Request: {request.Method} {request.RequestUri}");
+
+ // 调用管道中的下一个处理器,并获取响应
+ var response = await base.SendAsync(request, cancellationToken);
+
+ // 记录响应信息
+ Console.WriteLine($"Response: {response.StatusCode}");
+
+ return response;
+ }
+ }
+
+}
diff --git a/HttpClientStudy.UnitTest/DelegatingHandlerTest.cs b/HttpClientStudy.UnitTest/DelegatingHandlerTest.cs
new file mode 100644
index 0000000..3d1a769
--- /dev/null
+++ b/HttpClientStudy.UnitTest/DelegatingHandlerTest.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+
+using Microsoft.Extensions.Logging;
+
+namespace HttpClientStudy.UnitTest
+{
+ public class DelegatingHandlerTest
+ {
+ private readonly ITestOutputHelper _logger;
+ public DelegatingHandlerTest(ITestOutputHelper outputHelper)
+ {
+ _logger = outputHelper;
+ }
+
+ [Fact]
+ public async Task Test()
+ {
+ //构建管道
+ var handler = new HandlerA()
+ {
+ //相当于下一个中间件(管道)
+ InnerHandler = new HandlerB()
+ };
+
+ HttpClient httpClient = new HttpClient(handler);
+
+ var sd = await httpClient.GetAsync("http://127.0.0.1");
+ var contentText = await sd.Content.ReadAsStringAsync();
+
+ _logger.WriteLine(contentText);
+ }
+ }
+
+ public class HandlerB : DelegatingHandler
+ {
+ protected override async Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ InnerHandler = new SocketsHttpHandler() { };
+
+ //请求前业务
+
+ var response = await base.SendAsync(request, cancellationToken);
+
+ //响应后业务
+
+ return response;
+ }
+ }
+
+ public class HandlerA : DelegatingHandler
+ {
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ //请求前业务
+
+ var response = await base.SendAsync(request, cancellationToken);
+
+ //响应后业务
+
+ return response;
+ }
+ }
+}
diff --git a/HttpClientStudy.UnitTest/HttpClientQuestTest.cs b/HttpClientStudy.UnitTest/HttpClientQuestTest.cs
new file mode 100644
index 0000000..d4725d2
--- /dev/null
+++ b/HttpClientStudy.UnitTest/HttpClientQuestTest.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Net.Http.Json;
+using System.Net;
+using Newtonsoft.Json;
+using Microsoft.AspNetCore.Mvc;
+using System.Text.Json;
+using System.Security.Authentication.ExtendedProtection;
+using Newtonsoft.Json.Linq;
+using System.Text.Json.Serialization.Metadata;
+
+namespace HttpClientStudy.UnitTest
+{
+ ///
+ /// HttpClient 常见问题测试
+ ///
+ public class HttpClientQuestTest
+ {
+ private readonly ITestOutputHelper _logger;
+
+ public HttpClientQuestTest(ITestOutputHelper outputHelper)
+ {
+ _logger = outputHelper;
+ }
+
+ ///
+ /// 多HttpClient实例问题
+ /// 1、HttpClient虽然继承了 IDisposable 接口,但它是可以被共享的,且线程安全。Using使用并不能立即释放
+ /// 2、网络特性:虽然HttpClient客户端断开,但Web服务并不知道,连接依然存在,状态为 “ TIME_WAIT”(继续等待看是否还有延迟的包会传输过来。)
+ /// Windows默认为 240s
+ /// 引发常见问题:
+ /// 1、HttpClient 多实例并存,有很大资源消耗;
+ /// 2、在高并发的情况下,连接来不及释放, socket 被耗尽: 程序异常
+ /// 3、连带着会出现“各种套接字问题”
+ ///
+ /// 查看问题:
+ /// 程序并发或多次请求后,通过 netstate 查看下 TCP 连接情况:有很多 TIME_WAIT 状态连接;很可能程序异常;
+ ///
+ /// 解决:
+ /// 1、复用HttpClient
+ /// 2、HttpClientFactory
+ /// 3、解决DNS问题可以给HttpClient传参:SocketsHttpHandler
+ ///
+ ///
+ [Fact]
+ public async Task Multi_ClientObject_Test()
+ {
+ for (int i = 0; i < 1000; i++)
+ {
+ HttpClient httpClient = new HttpClient();
+
+ var responseMessage = await httpClient.GetAsync("https://www.baidu.com");
+
+ responseMessage.EnsureSuccessStatusCode();
+ }
+ }
+
+ [Fact]
+ public async Task Multi_ClientObject2_Test()
+ {
+ HttpClient httpClient = new HttpClient()
+ {
+ BaseAddress = new Uri("https://www.baidu.com")
+ };
+ for (int i = 0; i < 10000; i++)
+ {
+ var responseMessage = await httpClient.GetAsync("");
+
+ responseMessage.EnsureSuccessStatusCode();
+ }
+ }
+ }
+}
diff --git a/HttpClientStudy.UnitTest/PipelineClientTest.cs b/HttpClientStudy.UnitTest/PipelineClientTest.cs
new file mode 100644
index 0000000..8564224
--- /dev/null
+++ b/HttpClientStudy.UnitTest/PipelineClientTest.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HttpClientStudy.UnitTest
+{
+ public class PipelineClientTest
+ {
+ public PipelineClientTest() { }
+
+ [Fact]
+ public async Task Test()
+ {
+ HttpClient client = new PipelineClient().CreateHttpClient();
+
+ var r = await client.GetAsync("https://www.baidu.com");
+ r.EnsureSuccessStatusCode();
+
+
+ }
+ }
+}