.NET Core中HttpClient并发请求超20次崩溃的优化方案咨询
问题场景
在.NET Core中通过依赖注入封装MyHttpService使用HttpClient发起HTTP请求,使用JMeter进行压测时,并发20或50次请求程序即崩溃,抛出远程主机强迫关闭连接的异常。
相关代码
MyHttpService代码
namespace WebApplication1.UComon { public class MyHttpService { private readonly HttpClient _httpClient; public MyHttpService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<string> GetExternalData(string url) { var response = await _httpClient.GetAsync(url); if (response.IsSuccessStatusCode) { return await response.Content.ReadAsStringAsync(); } else { return null; } } } }
TestController代码
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using WebApplication1.UComon; namespace WebApplication1.Controllers { [Route("api/[controller]")] [ApiController] public class TestController : ControllerBase { private readonly MyHttpService _httpService; public TestController(MyHttpService httpService) { _httpService = httpService; } #region 测试httpclient [HttpGet, Route("PostHttp")] public IActionResult PostHttp() { string responseBody = ""; responseBody = _httpService.GetExternalData("https://www.baidu.com/").Result; return Ok(responseBody); } #endregion } }
抛出异常
System.AggregateException HResult=0x80131500
Message=发生一个或多个错误。(发送请求时出错。)
Source=System.Private.CoreLib
StackTrace: 在 System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) 在 System.Threading.Tasks.Task`1.get_Result()
内部异常 1: HttpRequestException: 发送请求时出错。
内部异常 2: IOException: 无法从传输连接读取数据: 远程主机强迫关闭了一个现有的连接。
内部异常 3: SocketException: 远程主机强迫关闭了一个现有的连接。
解决方案
1. 修复异步代码阻塞问题
控制器的PostHttp方法为同步方法,但调用异步方法时使用.Result阻塞线程,并发场景下会导致线程池耗尽,进而引发连接超时或被远程服务器关闭。将控制器方法改为异步实现:
[HttpGet, Route("PostHttp")] public async Task<IActionResult> PostHttp() { string responseBody = await _httpService.GetExternalData("https://www.baidu.com/"); return Ok(responseBody); }
2. 调整HttpClient连接数限制
默认情况下,HttpClient的MaxConnectionsPerServer值较低(通常为2),并发请求时会导致连接排队,远程服务器可能因超时主动关闭连接。在依赖注入配置时调整该值:
// Program.cs中配置 builder.Services.AddHttpClient<MyHttpService>() .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { MaxConnectionsPerServer = 100 // 根据实际并发需求调整 });
3. 增强异常处理与重试机制
针对远程服务器偶尔断开连接的情况,可添加重试逻辑提升稳定性。例如手动捕获异常并重试:
// 在MyHttpService中添加简单重试逻辑 public async Task<string> GetExternalData(string url, int retryCount = 2) { for (int i = 0; i <= retryCount; i++) { try { var response = await _httpClient.GetAsync(url); if (response.IsSuccessStatusCode) { return await response.Content.ReadAsStringAsync(); } } catch (SocketException) when (i < retryCount) { await Task.Delay(100); continue; } } return null; }
内容的提问来源于stack exchange,提问作者codesix

