前言 HttpClient 是 .NET Framework、.NET Core 或 .NET 5以上版本中的一個類,用於向 Web API 發送 HTTP 請求並接收響應。它提供了一些簡單易用的方法,如 GET、POST、PUT 和 DELETE,可以很容易地構造和發送 HTTP 請求,並處理響應 ...
前言
HttpClient 是 .NET Framework、.NET Core 或 .NET 5以上版本中的一個類,用於向 Web API 發送 HTTP 請求並接收響應。它提供了一些簡單易用的方法,如 GET、POST、PUT 和 DELETE,可以很容易地構造和發送 HTTP 請求,並處理響應數據。它是我們比較常用的官方HTTP請求組件,那麼你們都正確使用了嗎?本文將探討HttpClient的正確使用。
環境準備
首先我們用vs2022創建一個帶預設 WeatherForcast 模板的 Web API 應用程式,以及一個普通的API的程式,項目使用的是.NET6。
項目結構如下
兩個項目的功能點:
HttpClientTest - 返回天氣預報的Web API
HttpClientTest2 -這個項目將用HttpClient來請求HttpClientTest 的天氣預備。
接下來我們用4種方法來說明HttpClient的正確使用方法。
方法1
我們首先在HttpClientTest2 創建HttpClientTestController類,並寫一個請求天氣預備的方法,代碼如下:
namespace HttpClientTest2.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class HttpClientTestController : ControllerBase
{
[HttpGet]
public async Task<string> TestHttpClient()
{
var url = "https://localhost:7281/WeatherForecast";
#region 版本1
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync();
#endregion
}
}
}
代碼寫完後,我們設置多項目啟動,讓這兩個項目同時啟動。
項目啟動後,執行項目HttpClientTest2 的TestHttpClient請求介面。多執行幾次。主要看看HttpClient後臺的執行情況。這裡可以用netstat來檢查http的請求情況。
打開一個CMD控制台程式。輸入如下代碼:
netstat -na | find "7281"
7281埠是我們請求站點HttpClientTest。多次點擊的效果如下:
由上面可以看出有多個請求,說明請求未關閉。接下來換第二種方法。
方法2
使用using命令來實現請求結束關閉請求,代碼如下:
#region 版本2
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
#endregion
//歡迎公眾號:DOTNET開發跳槽
同樣我們多次請求,結果如下:
在這裡可以看到狀態“TIME_WAIT”,說明鏈接已經關閉,但實際情況鏈接還是占用著埠,在資源耗盡才會釋放。這就是套連接的問題,套接字耗儘是指伺服器上的可用套接字資源已經全部被占用,無法為新的連接提供服務。在 TCP/IP 網路通信中,每個埠上最多只能建立一個連接,這就限制了伺服器可以處理的連接數。當伺服器負載過高時,就可能導致套接字資源緊張,進而引發套接字耗盡問題。針對上面問題,繼續對HttpClient 改進。
方法3
這裡我們使用單例模式試一試。代碼如下:
public class HttpClientTestController : ControllerBase
{
private static HttpClient _httpClient;
static HttpClientTestController()
{
_httpClient = new HttpClient();
}
//註意:有許多方法可以實現單例模式。在這裡使用了靜態實例方法。
[HttpGet]
public async Task<string> TestHttpClient()
{
var url = "https://localhost:7281/WeatherForecast";
#region 版本3
//var response = await _httpClient.GetAsync(url);
//return await response.Content.ReadAsStringAsync();
#endregion
}
}
代碼編寫完成後我們再試一試,結果如下:
因為使用了單例模式,沒有創建新實例使用了相同的連接。這種方法解決了套接字耗盡問題。但是,我們註意到有一個狀態為“已建立”的開放連接。如果有DNS更改或與網路相關的更改可能會影響連接,應用程式可能會失敗,需要重新啟動應用程式才能解決。這個方法也不是最理想的。
方法4
HttpClient是.NET內置方法,這裡可以通過使用 IHttpClientFactory 介面來實現,從而避免上面的問題。代碼如下:
public class HttpClientTestController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
public HttpClientTestController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<string> TestHttpClient()
{
var url = "https://localhost:7281/WeatherForecast";
#region 版本4
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync();
#endregion
}
//歡迎公眾號:DOTNET開發跳槽
使用IHttpClientFactory 的話,需要在Program.cs 中註入,代碼如下:
builder.Services.AddHttpClient();
同樣多次請求,然後執行netstat命令。效果如下:
從請求的狀態來看,通過使用 _httpClientFactory.CreateClient() 完美解決問題。
結語
本文用四種方法漸進講述了HttpClient的使用方法以及在使用過程中的問題,最終用IHttpClientFactory解決了出現的問題。希望本文對你有所收穫,歡迎留言或者吐槽。
源碼地址:https://github.com/xbhp/webapitest
參考:微軟官方文檔
來源公眾號:DotNet開發跳槽