在很多时候我们在不同的服务之间需要通过HttpClient进行及时通讯,在我们的代码中我们会创建自己的HttpClient对象然后去跨领域额进行数据的交互,但是往往由于一个项目有多个人开发所以在开发中没有人经常会因为不同的业务请求去写不同的代码,然后就会造成各种风格的HttpClient的跨域请求,最重要的是由于每个人对HttpClient的理解程度不同所以写出来的代码可能质量上会有参差不齐,即使代码能够达到要求往往也显得非常臃肿,重复高我们在正式介绍Refit这个项目之前,我们来看看我们在项目中常用的调用方式,后面再来介绍这种处理方式的弊端以及后面集成了Refit以后我们代码的质量能够有哪些程度的提高。
一 常规创建方式
在常规的方式中我们一般使用IHttpClientFactory来创建HttpClient对象,然后使用这个对象来发送和接收消息,至于为什么要使用这个接口来创建HttpClient对象而不是使用using new HttpClient的原因请点击这里了解更多的信息,我们先来看下面的这个例子。
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using System.Web; using Abp.Domain.Services; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace Sunlight.Dms.Parts.Domain.Web { /// <summary> /// HttpClient的帮助类 /// </summary> public class DcsPartClientService : DomainService { private readonly HttpClient _httpClient; private readonly ILogger<DcsPartClientService> _loggerHelper; public DcsPartClientService(IHttpClientFactory httpClientFactory, ILogger<DcsPartClientService> loggerHelper) { _loggerHelper = loggerHelper; _httpClient = httpClientFactory.CreateClient(PartsConsts.DcsPartClientName); if (_httpClient.BaseAddress == null) { throw new ArgumentNullException(nameof(httpClientFactory), $"没有配置名称为 {PartsConsts.DcsPartClientName} 的HttpClient,或者接口服务的地址为空"); } } /// <summary> /// Post请求返回实体 /// </summary> /// <param name="relativeUrl">请求相对路径</param> /// <param name="postObj">请求数据</param> /// <returns>实体T</returns> public async Task<List<T>> PostResponse<T>(string relativeUrl, object postObj) where T : class { var postData = JsonConvert.SerializeObject(postObj); _httpClient.DefaultRequestHeaders.Add("user-agent", "Dcs-Parts"); _httpClient.CancelPendingRequests(); _httpClient.DefaultRequestHeaders.Clear(); HttpContent httpContent = new StringContent(postData); httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var result = default(List<T>); var response = await _httpClient.PostAsync(_httpClient.BaseAddress + relativeUrl, httpContent); if (response.StatusCode == HttpStatusCode.NotFound) { throw new ValidationException("找不到对应的DcsParts服务"); } var responseContent = await response.Content.ReadAsAsync<ReceiveResponseBody<List<T>>>(); if (response.IsSuccessStatusCode) { result = responseContent?.Payload; } else { if (!string.IsNullOrWhiteSpace(responseContent?.Message)) { throw new ValidationException(responseContent.Message); } _loggerHelper.LogDebug($"请求返回结果:{0} 请求内容:{1}", response.StatusCode, postData); } return await Task.FromResult(result); } public async Task<List<T>> GetResponse<T>(string relativeUrl, object queryObj) where T : class { var queryData = ModelToUriQueryParam(queryObj); _httpClient.DefaultRequestHeaders.Add("user-agent", "Dcs-Parts"); _httpClient.CancelPendingRequests(); _httpClient.DefaultRequestHeaders.Clear(); _httpClient.DefaultRequestHeaders.Add("accept", "application/json"); var result = default(List<T>); var response = await _httpClient.GetAsync(_httpClient.BaseAddress + relativeUrl + queryData); if (response.StatusCode == HttpStatusCode.NotFound) { throw new ValidationException("找不到对应的DcsParts服务"); } var responseContent = await response.Content.ReadAsAsync<ReceiveResponseBody<List<T>>>(); if (response.IsSuccessStatusCode) { result = responseContent?.Payload; } else { if (!string.IsNullOrWhiteSpace(responseContent?.Message)) { throw new ValidationException(responseContent.Message); &nb<a style="color:transparent">本文来源gao($daima.com搞@代@#码$网</a>sp; } } return await Task.FromResult(result); } private string ModelToUriQueryParam<T>(T t, string url = "") { var properties = t.GetType().GetProperties(); var sb = new StringBuilder(); sb.Append(url); sb.Append("?"); foreach (var p in properties) { var v = p.GetValue(t, null); if (v == null) continue; sb.Append(p.Name); sb.Append("="); sb.Append(HttpUtility.UrlEncode(v.ToString())); sb.Append("&"); } sb.Remove(sb.Length - 1, 1); return sb.ToString(); } } public class ReceiveResponseBody<T> where T : class { public string Message { get; set; } public T Payload { get; set; } } public class ReceiveResponseBody { public string Message { get; set; } } }