main
wanggaofeng
parent b188374b85
commit c4cd9f08d6

@ -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
{
/// <summary>
/// 管道方式 HttpClient客户端
/// </summary>
public class PipelineClient
{
public List<DelegatingHandler> HttpMessageHandlers { get; set; }
public PipelineClient()
{
HttpMessageHandlers = new List<DelegatingHandler>()
{
new CustomHeadersHandler(),
new LoggingHandler(),
};
}
public PipelineClient(List<DelegatingHandler> httpMessageHandlers)
{
HttpMessageHandlers = httpMessageHandlers;
if (httpMessageHandlers == null || httpMessageHandlers?.Count == 0)
{
HttpMessageHandlers = new List<DelegatingHandler>();
}
}
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;
}
}
/// <summary>
/// 默认处理器1 - 添加自定义请求头
/// </summary>
public class CustomHeadersHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// 在请求中添加自定义头部
request.Headers.Add("X-Custom-Header", "CustomValue");
// 调用管道中的下一个处理器
return await base.SendAsync(request, cancellationToken);
//响应信息(可不处理)
}
}
/// <summary>
/// 默认处理器1 - 简单的日志记录
/// </summary>
public class LoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> 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;
}
}
}

@ -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<HttpResponseMessage> 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<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//请求前业务
var response = await base.SendAsync(request, cancellationToken);
//响应后业务
return response;
}
}
}

@ -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
{
/// <summary>
/// HttpClient 常见问题测试
/// </summary>
public class HttpClientQuestTest
{
private readonly ITestOutputHelper _logger;
public HttpClientQuestTest(ITestOutputHelper outputHelper)
{
_logger = outputHelper;
}
/// <summary>
/// 多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
/// </summary>
/// <returns></returns>
[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();
}
}
}
}

@ -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();
}
}
}
Loading…
Cancel
Save