Asp.Net Core中HttpClient的使用方式

  在.Net Core应用开发中,调用第三方接口也是常有的事情,HttpClient使用人数、使用频率算是最高的一种了,在.Net Core中,HttpClient的使用方式随着版本的升级也发生了一些变化,本次就讲解一下Asp.Net Core2.1先后使用的两种方式。html

 

1、原先HttpClient使用方式

   通常来说,喜欢要用的时候才会选择去获取资源,所以,当在有需求时才会用HttpClient去调用资源,便会使用以下这种方式或其它方式获取资源。java

//do something...
using (var httpClient = new HttpClient())
{
    var requestUri = "http://aspnetcore.online/api/resource/getresource";
    var httpResponseMessage = await httpClient.GetAsync(requestUri);
    //do something...

    return Ok(httpResponseMessage);
}

  若是能够正常访问目标地址的话,则会返回相应的资源信息。  git

  

  又如Post方式提交并返回相应的内容,都是能够直接使用。github

//do something...
using (var httpClient = new HttpClient())
{
    var requestUri = "http://aspnetcore.online/api/resource/postresource";
    var httpResponseMessage = await httpClient.PostAsJsonAsync(requestUri,"星城软件");
    //do something...

    return Ok(httpResponseMessage);
}

   可是这种状况下会出现一个严重的问题,在不停的调用情形下,tcp链接数会被耗尽,虽然使用using方式调用HttpClient并在退出前调用Dispose()方法将HttpClient释放了,可是tcp链接仍然处于保持状态,在240s后才会自动断开,这里就涉及到一个链接状态了,首先得理解下http的工做原理,http协议是创建在tcp协议基础之上,当浏览器须要从服务器获取数据的时候,会发出一次http请求。http会经过tcp创建起一个到服务器的链接通道,当本次请求须要的数据完毕后,http会当即将tcp链接断开,这个过程是很短的。因此http链接是一种短链接,是一种无状态的链接。可是tcp的链接只要咱们不经过代码把链接关闭,这个链接就会在客户端和服务端的进程中一直存在,相关状态数据会一直保存着,直到无响应状态持续了默认关闭时间后自动断开。api

   

  当短时间请求量过大时,这就可能致使了"套接字资源耗尽异常",所以,为了解决这个问题,想到不释放HttpClient,将它做为单例一直使用,实现单例方式有不少种。浏览器

  如使用单例模式,只生成一个HttpClient服务器

private static HttpClient _httpClient = null;
public HttpClient CreateHttpClient()
{
    if (_httpClient == null) _httpClient = new HttpClient();
    return _httpClient;
}

   亦或是在初始化时完成单例注入,建立一个IHttpClient接口,及相应的实现StandardHttpClient,实现类种加入HttpClient属性,在实现类构造函数中完成初始化后即可直接使用该实现类完成资源请求工做。微信

//在startup中完成单例注入
services.AddSingleton<IHttpClient, StandardHttpClient>();

public interface IHttpClient
{
    //do something
}

public class StandardHttpClient : IHttpClient
{
    private HttpClient _client;

    public StandardHttpClient()
    {
        _client = new HttpClient();
    }

    //do something...
}

   虽然这样解决了"套接字资源耗尽异常",可是又带来了新的问题,熬不过DNS生存时间(TTL),当主机 DNS 更新时,又可能产生异常,提示没法解析主机名称,由于单例HttpClient不会随着主机DNS更新而更新,Singleton HttpClient doesn't respect DNS changesasync

An error occurred while sending the request. Couldn't resolve host name An error occurred while sending the request. Couldn't resolve host name

 

2、现有HttpClient使用方式

   在.Net Core2.1后,微软引入了HttpClientFactory完全解决这个问题,工厂模式的职责是负责建立对象,这个类主要负责建立HttpClient实例tcp

  首先在StartUp中注册,可能会提示安装这个Nuget包

 services.AddHttpClient();

  该方法内部实现过程能够浏览:http://www.javashuo.com/article/p-hiikwwjv-mv.html

  其次,在须要使用时,使用构造函数注入便可

[Route("api/[controller]")]
[ApiController]
public class HttpClientController : ControllerBase
{
    IHttpClientFactory _httpClientFactory;

    public HttpClientController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    [HttpGet]
    [Route(nameof(Index))]
    public async Task<IActionResult> Index()
    {
        var client = _httpClientFactory.CreateClient();
        var result = await client.GetAsync("http://aspnetcore.online/api/resource/getresource");
        return Ok(result);
    }
}

  具体实现原理简述为:HttpClientFactory内部管理着一个链接句柄池,对每个HttpClient使用一个句柄进行跟踪管理,当该实例使用完毕后,句柄仍然控制资源释放,在短时间大量处理时,能够将这部分句柄完成对不一样实例的跟踪管理,使得句柄,也就是相应的套接字生命周期延长,对套接字完成了复用。

 

 近日,长沙.NET技术社区已经创建,微信群:长沙.NET社区一群已满,若有须要来长沙发展或是回归长沙能够进入二群,加一下我来邀请进去。各大城市间的人才拉锯战进行中,无论是什么行业,什么职业,长沙都应留住人才,培养人才

 

2019-02-26,望技术有成后能回来看见本身的脚步
相关文章
相关标签/搜索