.NetCore簡單封裝基於IHttpClientFactory的HttpClient請求


IHttpClientFactory是什么?為什么出現了IHttpClientFactory

一、IHttpClientFactory是什么?

IHttpClientFactory是.netcore2.1才開始引入的,是HttpClient的工廠接口,它為我們提供了獲取HttpClient的接口,它幫助我們維護HttpClient的生命周期。當我們需要HttpClient訪問網絡時,它會自動幫我們獲取或者是創建HttpClient(存在空閑的HttpClient時,直接提供;當不存在可用的HttpClient時自動創建)。它相當於HttpClient池。

二、為什么出現IHttpClientFactory?

傳統的HttpClient創建后,其占用了Socket資源並且其不會是及時的回收。我們每次new一個HttpClient時是一個全新的對象,所以在高並發下又是會導致socket資源耗盡(Unable to connect to the remote serverSystem.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.)。而如果采用單例或者靜態的HttpClient,卻達不到高效的使用網絡請求,而且當訪問不同的url時,單例或者靜態的HttpClient往往會導致訪問混亂而出現錯誤。

 

.NetCore簡單封裝基於IHttpClientFactory的HttpClient請求

  1  public class HttpWebClient
  2     {
  3 
  4         private IHttpClientFactory _httpClientFactory;
  5         private readonly ILogger<HttpWebClient> _logger;
  6         public HttpWebClient(IHttpClientFactory httpClientFactory, ILogger<HttpWebClient> logger)
  7         {
  8             this._httpClientFactory = httpClientFactory;
  9             this._logger = logger;
 10         }
 11 
 12         /// <summary>
 13         /// Get
 14         /// </summary>
 15         /// <param name="url"></param>
 16         /// <param name="dicHeaders"></param>
 17         /// <param name="timeoutSecond"></param>
 18         /// <returns></returns>
 19         public async Task<T> GetAsync<T>(string url, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
 20         {
 21             try
 22             {
 23                 var client = BuildHttpClient(dicHeaders, timeoutSecond);
 24                 var response = await client.GetAsync(url);
 25                 var responseContent = await response.Content.ReadAsStringAsync();
 26                 if (response.IsSuccessStatusCode)
 27                 {
 28                     return JsonUtil.Deserialize<T>(responseContent);
 29                 }
 30                 else
 31                 {
 32                     throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
 33                 }
 34             }
 35             catch (Exception ex)
 36             {
 37                 _logger.LogError($"HttpGet:{url} Error:{ex.ToString()}");
 38                 throw new Exception($"HttpGet:{url} Error", ex);
 39             }
 40         }
 41         /// <summary>
 42         /// Post
 43         /// </summary>
 44         /// <param name="url"></param>
 45         /// <param name="requestBody"></param>
 46         /// <param name="dicHeaders"></param>
 47         /// <param name="timeoutSecond"></param>
 48         /// <returns></returns>
 49         public async Task<T> PostAsync<T>(string url, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
 50         {
 51             try
 52             {
 53                 var client = BuildHttpClient(null, timeoutSecond);
 54                 var requestContent = GenerateStringContent(requestBody, dicHeaders);
 55                 var response = await client.PostAsync(url, requestContent);
 56                 var responseContent = await response.Content.ReadAsStringAsync();
 57                 if (response.IsSuccessStatusCode)
 58                 {
 59                     var result = JsonUtil.Deserialize<T>(responseContent);
 60                     return result;
 61                 }
 62                 else
 63                 {
 64                     throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
 65                 }
 66             }
 67             catch (Exception ex)
 68             {
 69                 _logger.LogError($"HttpPost:{url},body:{requestBody} Error:{ex.ToString()}");
 70                 throw new Exception($"HttpPost:{url} Error", ex);
 71             }
 72         }
 73         /// <summary>
 74         /// Put
 75         /// </summary>
 76         /// <param name="url"></param>
 77         /// <param name="requestBody"></param>
 78         /// <param name="dicHeaders"></param>
 79         /// <param name="timeoutSecond"></param>
 80         /// <returns></returns>
 81         public async Task<T> PutAsync<T>(string url, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
 82         {
 83             try
 84             {
 85                 var client = BuildHttpClient(null, timeoutSecond);
 86                 var requestContent = GenerateStringContent(requestBody, dicHeaders);
 87                 var response = await client.PutAsync(url, requestContent);
 88                 var responseContent = await response.Content.ReadAsStringAsync();
 89                 if (response.IsSuccessStatusCode)
 90                 {
 91                     var result = JsonUtil.Deserialize<T>(responseContent);
 92                     return result;
 93                 }
 94                 else
 95                 {
 96                     throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
 97                 }
 98             }
 99             catch (Exception ex)
100             {
101                 _logger.LogError($"HttpPut:{url},Body:{requestBody},  Error:{ex.ToString()}");
102                 throw new Exception($"HttpPut:{url} Error", ex);
103             }
104         }
105 
106         /// <summary>
107         /// Patch
108         /// </summary>
109         /// <param name="url"></param>
110         /// <param name="requestString"></param>
111         /// <param name="dicHeaders"></param>
112         /// <param name="timeoutSecond"></param>
113         /// <returns></returns>
114         public async Task<T> PatchAsync<T>(string url, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
115         {
116             try
117             {
118                 var client = BuildHttpClient(null, timeoutSecond);
119                 var requestContent = GenerateStringContent(requestBody, dicHeaders);
120                 var response = await client.PatchAsync(url, requestContent);
121                 var responseContent = await response.Content.ReadAsStringAsync();
122                 if (response.IsSuccessStatusCode)
123                 {
124                     var result = JsonUtil.Deserialize<T>(responseContent);
125                     return result;
126                 }
127                 else
128                 {
129                     throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
130                 }
131             }
132             catch (Exception ex)
133             {
134                 _logger.LogError($"HttpPatch:{url},body:{requestBody}, Error:{ex.ToString()}");
135                 throw new Exception($"HttpPatch:{url} Error", ex);
136             }
137         }
138         /// <summary>
139         /// Delete
140         /// </summary>
141         /// <param name="url"></param>
142         /// <param name="dicHeaders"></param>
143         /// <param name="timeoutSecond"></param>
144         /// <returns></returns>
145         public async Task<T> DeleteAsync<T>(string url, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
146         {
147             try
148             {
149                 var client = BuildHttpClient(dicHeaders, timeoutSecond);
150                 var response = await client.DeleteAsync(url);
151                 var responseContent = await response.Content.ReadAsStringAsync();
152                 if (response.IsSuccessStatusCode)
153                 {
154                     var result = JsonUtil.Deserialize<T>(responseContent);
155                     return result;
156                 }
157                 else
158                 {
159                     throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
160                 }
161             }
162             catch (Exception ex)
163             {
164                 _logger.LogError($"HttpDelete:{url}, Error:{ex.ToString()}");
165                 throw new Exception($"HttpDelete:{url} Error", ex);
166             }
167         }
168         /// <summary>
169         /// common request
170         /// </summary>
171         /// <param name="url"></param>
172         /// <param name="method"></param>
173         /// <param name="requestBody"></param>
174         /// <param name="dicHeaders"></param>
175         /// <param name="timeoutSecond"></param>
176         /// <returns></returns>
177         public async Task<T> ExecuteAsync<T>(string url, HttpMethod method, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
178         {
179             try
180             {
181                 var client = BuildHttpClient(null, timeoutSecond);
182                 var request = GenerateHttpRequestMessage(url, requestBody, method, dicHeaders);
183                 var response = await client.SendAsync(request);
184                 var responseContent = await response.Content.ReadAsStringAsync();
185                 if (response.IsSuccessStatusCode)
186                 {
187                     var result = JsonUtil.Deserialize<T>(responseContent);
188                     return result;
189                 }
190                 else
191                 {
192                     throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
193                 }
194             }
195             catch (Exception ex)
196             {
197                 _logger.LogError($"{method.ToString()}:{url},body:{requestBody}, Error:{ex.ToString()}");
198                 throw new Exception($"{method.ToString()}:{url} Error", ex);
199             }
200 
201         }
202         /// <summary>
203         /// Build HttpClient
204         /// </summary>
205         /// <param name="timeoutSecond"></param>
206         /// <returns></returns>
207         private HttpClient BuildHttpClient(Dictionary<string, string> dicDefaultHeaders, int? timeoutSecond)
208         {
209             var httpClient = _httpClientFactory.CreateClient();
210             httpClient.DefaultRequestHeaders.Clear();   //in order that the client is not affected by the last request,it need to clear DefaultRequestHeaders
211             httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
212             if (dicDefaultHeaders != null)
213             {
214                 foreach (var headerItem in dicDefaultHeaders)
215                 {
216                     if (!httpClient.DefaultRequestHeaders.Contains(headerItem.Key))
217                     {
218                         httpClient.DefaultRequestHeaders.Add(headerItem.Key, headerItem.Value);
219                     }
220                 }
221             }
222             if (timeoutSecond != (int?)null)
223             {
224                 httpClient.Timeout = TimeSpan.FromSeconds(timeoutSecond.Value);
225             }
226             return httpClient;
227         }
228 
229         /// <summary>
230         /// Generate HttpRequestMessage
231         /// </summary>
232         /// <param name="url"></param>
233         /// <param name="requestBody"></param>
234         /// <param name="method"></param>
235         /// <param name="dicHeaders"></param>
236         /// <returns></returns>
237         private HttpRequestMessage GenerateHttpRequestMessage(string url, string requestBody, HttpMethod method, Dictionary<string, string> dicHeaders)
238         {
239             var request = new HttpRequestMessage(method, url);
240             if (!string.IsNullOrEmpty(requestBody))
241             {
242                 request.Content = new StringContent(requestBody);
243             }
244             if (dicHeaders != null)
245             {
246                 foreach (var header in dicHeaders)
247                 {
248                     request.Headers.Add(header.Key, header.Value);
249                 }
250             }
251             return request;
252         }
253         /// <summary>
254         ///  Generate StringContent
255         /// </summary>
256         /// <param name="requestBody"></param>
257         /// <param name="dicHeaders"></param>
258         /// <returns></returns>
259         private StringContent GenerateStringContent(string requestBody, Dictionary<string, string> dicHeaders)
260         {
261             var content = new StringContent(requestBody);
262             if (dicHeaders != null)
263             {
264                 foreach (var headerItem in dicHeaders)
265                 {
266                     content.Headers.Add(headerItem.Key, headerItem.Value);
267                 }
268             }
269             return content;
270         }
271 
272 
273     }

 

 

CustomerHttpException類的簡單定義
 1     public class CustomerHttpException : Exception
 2     {
 3         public string ErrorCode { get; set; }
 4         public string ErrorMessage { get; set; }
 5         public CustomerHttpException() : base()
 6         { }
 7         public CustomerHttpException(string errorCode, string errorMessage) : base()
 8         {
 9             this.ErrorCode = errorCode;
10             this.ErrorMessage = ErrorMessage;
11         }
12     }

 

以上是簡單的Http請求封裝。其中一些值得注意的點

1、創建的HttpClient是由HttpClientFactory統一管理的,所以當指定了DefaultRequestHeaders時,下次再次從HttpClientFactory中獲取時可能帶着上次的Header信息。所以需要對其進行Clear。

2、封裝了統一的調用接口ExecuteAsync,建議采用該接口進行http請求,此時就不會去配置DefaultRequestHeaders,而是將Header信息配置在請求信息中。

3、自定義了CustomerHttpException,主要是為了支持ResultFul風格的api。通過外層捕獲CustomerHttpException,從而解析出具體的錯誤信息。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM