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,望技術有成後能回來看見本身的腳步
相關文章
相關標籤/搜索