.NetCore简单封装基于IHttpClientFactory的HttpClient请求

.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,从而解析出具体的错误信息。

posted @ 2021-11-16 15:21  易胆大888  阅读(105)  评论(0编辑  收藏  举报