在.NET项目开发中,我们常用于发起HTTP请求HttpClient类由于先天缺陷,调用HttpClient的dispose方法后并不能立即释放套接字(Sokect)资源。
在频繁的发起HTTP请求的系统给中将会存在大量的处于处于TIME_WAIT状态的套接字资源,最终导致套接字资源被耗尽。为了解决这个问题,微软推出了IHttpClientFactory方案,大概意思就是将链接对象池化。、
具体使用案列如下,(本案列只简单封装了最常用的GET和POST请求方式,其他PUT、DELETE、PATCH如有需要请自行添加实现。)
代码中使用了Newtonsoft.Json。
1.在Startup中的ConfigureServices方法中注册IHttpClientFactory.和实现
public void ConfigureServices(IServiceCollection services) { //注册IHttpClientFactory services.AddHttpClient(); //注册IHttpClientFactory的实现到DI容器 services.AddTransient<HttpClientHelper>(); }
2.基于IHttpClientFactory的Helper类封装。
using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; namespace Research.Web.Common { /// <summary> /// 本案列只简单封装了最常用的GET和POST请求方式,其他PUT、DELETE、PATCH,请自行添加实现。 /// </summary> public class HttpClientHelper { private IHttpClientFactory _httpClientFactory; public HttpClientHelper(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } /// <summary> /// 发起GET异步请求 /// </summary> /// <typeparam name="T">返回类型</typeparam> /// <param name="httpClientFactory"></param> /// <param name="url">请求地址</param> /// <param name="headers">请求头信息</param> /// <param name="timeOut">请求超时时间,单位秒</param> /// <returns>返回string</returns> public async Task<string> GetAsync(string url, Dictionary<string, string> headers = null, int timeOut = 30) { var hostName = GetHostName(url); using (HttpClient client = _httpClientFactory.CreateClient(hostName)) { client.Timeout = TimeSpan.FromSeconds(timeOut); if (headers?.Count > 0) { foreach (string key in headers.Keys) { client.DefaultRequestHeaders.Add(key, headers[key]); } } using (HttpResponseMessage response = await client.GetAsync(url)) { if (response.IsSuccessstatusCode) { string responseString = await response.Content.ReadAsstringAsync(); return responseString; } else { return string.Empty; } } } } /// <summary> /// 发起GET异步请求 /// </summary> /// <typeparam name="T">返回类型</typeparam> /// <param name="httpClientFactory"></param> /// <param name="url">请求地址</param> /// <param name="headers">请求头信息</param> /// <param name="timeOut">请求超时时间,单位秒</param> /// <returns>返回T</returns> public async Task<T> GetAsync<T>(string url, Dictionary<string, string> headers = null, int timeOut = 30) where T : new() { string responseString = await GetAsync(url, headers, timeOut); if (!string.IsNullOrWhiteSpace(responseString)) { return JsonConvert.DeserializeObject<T>(responseString); } else { return default(T); } } /// <summary> /// 发起POST异步请求 /// </summary> /// <param name="httpClientFactory"></param> /// <param name="url">请求地址</param> /// <param name="body">POST提交的内容</param> /// <param name="bodyMediaType">POST内容的媒体类型,如:application/xml、application/json</param> /// <param name="responseContentType">HTTP响应上的content-type内容头的值,如:application/xml、application/json、application/text、application/x-www-form-urlencoded等</param> /// <param name="headers">请求头信息</param> /// <param name="timeOut">请求超时时间,单位秒</param> /// <returns>返回string</returns> public async Task<string> PostAsync(string url, string body, string bodyMediaType = null, string responseContentType = null, Dictionary<string, string> headers = null, int timeOut = 30) { var hostName = GetHostName(url); using (HttpClient client = _httpClientFactory.CreateClient(hostName)) { client.Timeout = TimeSpan.FromSeconds(timeOut); if (headers?.Count > 0) { foreach (string key in headers.Keys) { client.DefaultRequestHeaders.Add(key, headers[key]); } } var content = new StringContent(body, System.Text.Encoding.UTF8, mediaType: bodyMediaType); if (!string.IsNullOrWhiteSpace(responseContentType)) { content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(responseContentType); } using (HttpResponseMessage response = await client.PostAsync(url, content)) { if (response.IsSuccessstatusCode) { string responseString = await response.Content.ReadAsstringAsync(); return responseString; } else { return string.Empty; } } } } /// <summary> /// 发起POST异步请求 /// </summary> /// <typeparam name="T">返回类型</typeparam> /// <param name="httpClientFactory"></param> /// <param name="url">请求地址</param> /// <param name="body">POST提交的内容</param> /// <param name="bodyMediaType">POST内容的媒体类型,如:application/xml、application/json</param> /// <param name="responseContentType">HTTP响应上的content-type内容头的值,如:application/xml、application/json、application/text、application/x-www-form-urlencoded等</param> /// <param name="headers">请求头信息</param> /// <param name="timeOut">请求超时时间,单位秒</param> /// <returns>返回T</returns> public async Task<T> PostAsync<T>(string url, string body, string bodyMediaType = null, string responseContentType = null, Dictionary<string, string> headers = null, int timeOut = 30) where T : new() { string responseString = await PostAsync(url, body, bodyMediaType, responseContentType, headers, timeOut); if (!string.IsNullOrWhiteSpace(responseString)) { return JsonConvert.DeserializeObject<T>(responseString); } else { return default(T); } } #region 私有函数 /// <summary> /// 获取请求的主机名 /// </summary> /// <param name="url"></param> /// <returns></returns> private static string GetHostName(string url) { if (!string.IsNullOrWhiteSpace(url)) { return url.Replace("https://", "").Replace("http://", "").Split('/')[0]; } else { return "AnyHost"; } } #endregion } }
3.调用基于IHttpClientFactory的Helper类发起Http请求。
using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Research.Web.Common; namespace Research.Web.Controllers { [ApiExplorerSettings(GroupName = "Web")] [ApiController] [Route("Web")] public class WebeController : ControllerBase { private HttpClientHelper _httpClientHelper; /// <summary> /// 从DI容器中获取HttpClientHelper实列对象 /// </summary> /// <param name="httpClientHelper"></param> public WebeController(HttpClientHelper httpClientHelper) { this._httpClientHelper = httpClientHelper; } /// <summary> /// 测试异步HttpClient /// </summary> /// <returns></returns> [HttpGet("testhttpasync")] public async Task<JsonResult> TestAsyncHttpClientFactory() { var model = await _httpClientHelper.GetAsync<ResponseModel>("https://www.juhe.cn/_t"); return new JsonResult(model); } } }
4.通过SwaggerUI界面调用接口测试结果
原文地址:https://www.cnblogs.com/pudefu/p/14715146.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。