HttpClient问题

  • HttPClient使用完之后不会立即关闭开启网络连接时会占用底层socket资源,但在HttpClient调用其本身的Dispose方法时,并不能立刻释放该资源
  • 如果频繁的使用HttpClient,频繁的打开链接,关闭链接消耗就会很大

    HttpClientFactory

  • 在.NET Core 2.1版本之后引入的 HttpClientFactory解决了HttpClient的所有痛点。有了 HttpClientFactory,我们不需要关心如何创建HttpClient,又如何释放它。通过它可以创建具有特定业务的HttpClient,而且可以很友好的和 DI 容器结合使用,更为灵活。

  • HttpClientFactory 创建的HttpClient,也即是HttpClientHandler,只是这些个HttpClient被放到了“池子”中,工厂每次在create的时候会自动判断是新建还是复用。(默认生命周期为2min,默认的生命周期可以修改)

    服务配置

    新建一个类 用作service配置

    1. /// <summary>
    2. /// 初始化HttpClient配置
    3. /// </summary>
    4. /// <param name="services"></param>
    5. public static void AddHttpClientSevice(this IServiceCollection services)
    6. {
    7. if (services == null) throw new ArgumentNullException(nameof(services));
    8. //添加默认服务 没有指定服务名称的都可以使用默认服务
    9. services.AddHttpClient();//可以添加多个
    10. //获取自定义配置 每一个需要连接的对象都已使用指定名称的服务,所以服务需要命名
    11. var clientconfig = AppsettingConfig.HttpClientConfig;//我在appseeting中配置了是一个数组
    12. if (clientconfig?.Count > 0)
    13. {
    14. foreach (var item in clientconfig)
    15. {
    16. if (string.IsNullOrWhiteSpace(item.ServiceName)) continue;//检测服务名称
    17. services.AddHttpClient(item.ServiceName, client =>
    18. {
    19. client.BaseAddress = new Uri(item.BaseAddress);
    20. if (item.Timeout > 0)
    21. client.Timeout = TimeSpan.FromSeconds(item.Timeout);//设置超时
    22. if (item.DeafaultRequestHeader?.Count > 0)//添加默认header
    23. foreach (var header in item.DeafaultRequestHeader)
    24. {
    25. client.DefaultRequestHeaders.Add(header.Key, header.Value);//可以设置都有的Header 不能添加“Content-Type”
    26. }
    27. }).ConfigurePrimaryHttpMessageHandler(() =>
    28. {
    29. //配置代理 如果配有代理
    30. if (!item.Proxy.IsActive) return new HttpClientHandler();
    31. var hander = new HttpClientHandler()
    32. {
    33. AllowAutoRedirect = false,
    34. UseDefaultCredentials = true,
    35. };
    36. hander.Proxy = new WebProxy(item.Proxy.Host, item.Proxy.Port);//代理地址
    37. hander.Proxy.Credentials = new NetworkCredential(item.Proxy.UserName, item.Proxy.PassWord, item.Proxy.Domain);//账号。密码。域
    38. return hander;
    39. });
    40. }
    41. }
    42. }
    43. //注册封装类
    44. services.AddSingleton<IHttpHelper, HttpHelper>();
    45. }

    StartUp中添加服务

    //注册http请求服务
    services.AddHttpClientSevice();
    

    封装HttpHelper

    接口声明

    public interface IHttpHelper
      {
          /// <summary>
          /// Get请求
          /// </summary>
          /// <param name="url">完整的Url</param>
          /// <param name="headers">自定义header</param>
          /// <param name="servicename">服务名称</param>
          /// <returns></returns>
          public Task<HttpResponseMessage> GetAsync(string url, Dictionary<string, string> headers = null, string servicename = "");
          /// <summary>
          /// Post请求
          /// </summary>
          /// <param name="url">完整的Url</param>
          /// <param name="body">body体</param>
          /// <param name="headers">头</param>
          /// <param name="servicename">servicename</param>
          /// <returns></returns>
          public Task<HttpResponseMessage> PostAsync(string url, string body = "", Dictionary<string, string> headers = null, string servicename = "");
    
      }
    

    接口实现

    public class HttpHelper : IHttpHelper
      {
          private readonly IHttpClientFactory _httpClientFactory;
          private readonly ILogHelper _logHelper;
    
          public HttpHelper(IHttpClientFactory httpClientFactory, ILogHelper logHelper)
          {
              _httpClientFactory = httpClientFactory;
              _logHelper = logHelper;
          }
    
          /// <summary>
          /// Get请求
          /// </summary>
          /// <param name="url">完整的Url</param>
          /// <param name="headers">自定义header</param>
          /// <param name="servicename">服务名称</param>
          /// <returns></returns>
          public Task<HttpResponseMessage> GetAsync(string url, Dictionary<string, string> headers = null, string servicename = "")
          {
              try
              {
                  HttpClient client;
                  if (string.IsNullOrWhiteSpace(servicename))
                  {
                      client = _httpClientFactory.CreateClient();
                  }
                  else
                  {
                      client = _httpClientFactory.CreateClient(servicename);
                  }
                  if (headers?.Count > 0)
                  {
                      foreach (var item in headers)
                      {
                          client.DefaultRequestHeaders.Add(item.Key, item.Value);
                      }
                  }
    
                  return client.GetAsync(url);
              }
              catch (Exception ex)
              {
                  _logHelper.LogErr("HttpHelper.GetAsync", ex);
                  throw ex;
              }
          }
          /// <summary>
          /// Post请求
          /// </summary>
          /// <param name="url">完整的Url</param>
          /// <param name="body">body体</param>
          /// <param name="headers">头</param>
          /// <param name="servicename">servicename</param>
          /// <returns></returns>
          public Task<HttpResponseMessage> PostAsync(string url, string body = "", Dictionary<string, string> headers = null, string servicename = "")
          {
              try
              {
                  HttpClient client;
                  if (string.IsNullOrWhiteSpace(servicename))
                  {
                      client = _httpClientFactory.CreateClient();
                  }
                  else
                  {
                      client = _httpClientFactory.CreateClient(servicename);
                  }
                  if (headers?.Count > 0)
                  {
                      foreach (var item in headers)
                      {
                          client.DefaultRequestHeaders.Add(item.Key, item.Value);
                      }
                  }
                  var content = new StringContent(body, Encoding.UTF8, "application/json");
                  return client.PostAsync(url, content);
              }
              catch (Exception ex)
              {
                  _logHelper.LogErr("HttpHelper.PostAsync", ex);
                  throw ex;
              }
          }
    
      }
    

    最后直接用就好 可以对返回的HttpResponseMessage进行操作,比如判断StatusCode 读取返回值 Content.ReadAsStringAsync()