如何在Asp.Net Core项目中成功集成并使用Refit进行API调用?

2026-04-01 09:461阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2077个文字,预计阅读时间需要9分钟。

如何在Asp.Net Core项目中成功集成并使用Refit进行API调用?

目录+一+常规创建方式+1.1+注入IHttpClientFactory对象+1.2+配置HttpClient的BaseAddress+1.3+HttpClient进行数据的发送和接收+1.4+总结+二+使用Refit来创建HttpClient对象+2.1+引入Refit包+2.2+定义接口+2.3+注入“

目录
  •   一 常规创建方式
    •   1.1 注入IHttpClientFactory对象
    •   1.2 配置HttpClient的BaseAddress  
    •   1.3 HttpClient进行数据的发送和接收
    •   1.4 总结
  •   二 使用Refit来创建HttpClient对象
    •   2.1 引入Refit包
    •   2.2 定义接口
    •   2.3 注入接口并使用接口中的方法
    •   2.4 在Startup中配置基础配置信息
    •   2.5 注意事项

  在很多时候我们在不同的服务之间需要通过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 _blob-storage/", "DcsParts": "dcs-parts/", "DmsAfterSales": "dms-after-sales/" }

  有了这些我们就能够具备创建一个HttpClient对象的条件了,后面我们来看看我们怎么使用这个HttpClient进行发送和接收数据。

  1.3 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); }

  在上面的代码中我们模拟了一个Post请求,请求完成以后我们再使用ReadAsAsync的方法来异步接收另外一个域中的数据,然后我们根据返回的StatusCode来抛出不同的错误提示,并记录相关的日志信息并返回最终Post请求的结果,进而完成整个过程,在这个中间我们发送请求的时候需要注意一下内容:1 最终的完整版地址=BaseAddress+RelativeAddress,基地址是在appsetting.json中进行配置的,RelativeAddress是我们请求不同域的时候的相对地址,这个需要我们根据实际的业务来进行配置。2 请求的对象是我们将数据对象序列化成json后的结果,这两点需要特别注意。

  1.4 总结

  通过上面的讲述我们知道了如何完整的创建HttpClient以及通过创建的HttpClient如何收发数据,但同时我们也发现了通过上面的方式我们的缺点:如果一个业务中有大量的这种跨域请求整个代码显得非常臃肿并且由于不同开发人员的认知不同最终导致很容易出问题,那么我们是否有办法能够去解决上面的问题呢?Refit库的出现正好解决了这个问题,Refit通过这种申明式的方式能够很大程度上让代码更加简练明了而且提供了更加丰富的功能。

如何在Asp.Net Core项目中成功集成并使用Refit进行API调用?

  二 使用Refit来创建HttpClient对象

  2.1 引入Refit包

  在我们的项目中我们可以通过 <PackageReference Include="Refit" Version="XXX" />来快速引用Refit包,引用的方式这里便不再赘述。

  2.2 定义接口

  我们将我们业务中涉及到的方法定义在一个接口中,就像下面这样。

public interface IDmsAfterSalesApi { [Headers("User-Agent: Dms-Parts")] [Post("/internal/api/v1/customerAccounts/update")] Task<ResponseBody> UpdateCustomerAmount([Body]PartRetailSettlementModel input); [Headers("User-Agent: Dms-Parts")] [Post("/internal/api/v1/repairShortagePart/checkCustomerAccount")] Task<RepairShortagePartResponseBody> RepairShortagePartCheckCustomerAccount([Body]RepairShortagePartModel input); [Headers("User-Agent: Dms-Parts")] [Post("/internal/api/v1/vehiclesAndMemberCode/forCoupons")] Task<GetMemberCodeBrandCodeForVehicleBody> GetMemberCodeBrandCodeForVehicle(Guid vehicleId); }

  2.3 注入接口并使用接口中的方法

public class DmsAfterSalesClientService : DomainService { private readonly IDmsAfterSalesApi _api; private readonly ILogger<DcsPartClientService> _logger; private const string From = "Dms After Sales"; public DmsAfterSalesClientService(IDmsAfterSalesApi api, ILogger<DcsPartClientService> logger) { _api = api; _logger = logger; } private async Task<Exception> WrapException(ApiException exception) { if (exception.StatusCode == System.Net.HttpStatusCode.BadRequest) { var receivedBody = await exception.GetContentAsAsync<ResponseBody>(); return new ValidationException($"业务校验失败,{receivedBody.Message} ({From})", exception); } else { _logger.LogWarning(exception, "Call Dms After Sales API failed"); return new ApplicationException($"内部调用失败,{exception.Message} ({exception.StatusCode}) ({From})", exception); } } private Exception WrapException(HttpRequestException exception) { _logger.LogWarning(exception, "Call Dms After Sales API failed"); return new ApplicationException($"内部调用失败,{exception.Message} ({From})", exception); } public async Task UpdateCustomerAmount([Body] PartRetailSettlementModel input) { try { await _api.UpdateCustomerAmount(input); } catch (ApiException ex) { throw await WrapException(ex); } catch (HttpRequestException ex) { throw WrapException(ex); } } public async Task<decimal> RepairShortagePartCheckCustomerAccount([Body] RepairShortagePartModel input) { try { var result = await _api.RepairShortagePartCheckCustomerAccount(input); return result.Payload.BalanceAmount; } catch (ApiException ex) { throw await WrapException(ex); } catch (HttpRequestException ex) { throw WrapException(ex); } } public async Task<GetMemberCodeBrandCodeForVehicleOutput> GetMemberCodeBrandCodeForVehicle([Body]Guid vehicleId) { try { var result = await _api.GetMemberCodeBrandCodeForVehicle(vehicleId); return result.Payload; } catch (ApiException ex) { throw await WrapException(ex); } catch (HttpRequestException ex) { throw WrapException(ex); } } }

  在上面接口中定义好这个方法以后我们就可以直接在我们的领域类中引入这个接口IDmsAfterSalesApi ,然后就直接使用这个接口中的方法,讲到这里便有疑问,这个接口的实现到底在哪里?这里当我们定义好接口然后点击里面的方法转到实现的时候我们发现里面会转到一个叫做RefitStubs.g.cs的类中,然后自动的生成下面的方法。

/// <inheritdoc /> [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [Preserve] [global::System.Reflection.Obfuscation(Exclude=true)] partial class AutoGeneratedIDmsAfterSalesApi : IDmsAfterSalesApi { /// <inheritdoc /> public HttpClient Client { get; protected set; } readonly IRequestBuilder requestBuilder; /// <inheritdoc /> public AutoGeneratedIDmsAfterSalesApi(HttpClient client, IRequestBuilder requestBuilder) { Client = client; this.requestBuilder = requestBuilder; } /// <inheritdoc /> Task<ResponseBody> IDmsAfterSalesApi.UpdateCustomerAmount(PartRetailSettlementModel input) { var arguments = new object[] { input }; var func = requestBuilder.BuildRestResultFuncForMethod("UpdateCustomerAmount", new Type[] { typeof(PartRetailSettlementModel) }); return (Task<ResponseBody>)func(Client, arguments); } /// <inheritdoc /> Task<RepairShortagePartResponseBody> IDmsAfterSalesApi.RepairShortagePartCheckCustomerAccount(RepairShortagePartModel input) { var arguments = new object[] { input }; var func = requestBuilder.BuildRestResultFuncForMethod("RepairShortagePartCheckCustomerAccount", new Type[] { typeof(RepairShortagePartModel) }); return (Task<RepairShortagePartResponseBody>)func(Client, arguments); } /// <inheritdoc /> Task<GetMemberCodeBrandCodeForVehicleBody> IDmsAfterSalesApi.GetMemberCodeBrandCodeForVehicle(Guid vehicleId) { var arguments = new object[] { vehicleId }; var func = requestBuilder.BuildRestResultFuncForMethod("GetMemberCodeBrandCodeForVehicle", new Type[] { typeof(Guid) }); return (Task<GetMemberCodeBrandCodeForVehicleBody>)func(Client, arguments); } }  

  这里面的核心是调用一个BuildRestResultFuncForMethod的方法,后面我们再来分析这里面到底是怎么实现的,这里我们首先把这整个使用流程说完,之前我们说过Refit的很多配置都是通过标签的方式来注入进去的,这里包括请求类型、相对请求地址,那么我们的默认超时时间和BaseAddress到底是怎样来配置的呢?下面我们就来重点讲述。

  2.4 在Startup中配置基础配置信息

public IServiceProvider ConfigureServices(IServiceCollection services) { //refit dms after sales服务 services.AddRefitClient<IDmsAfterSalesApi>() .ConfigureHttpClient(c => { c.BaseAddress = new Uri(_appConfiguration["DependencyServices:DmsAfterSales"]); c.Timeout = TimeSpan.FromMilliseconds(_appConfiguration.GetValue<int>("AppSettings:ServiceTimeOutMs")); }); }

  这里我们看到通过一个AddRefitClient方法我们就能够去配置我们的基础信息,讲到这里我们是不是对整个过程都有一个清楚的认识呢?通过上下两种方式的对比,相信你对整个Refit的使用都有自己的理解。

  2.5 注意事项

  由于我们的Headers经常需要我们去配置一组数据,那么我们应该怎么配置多个项呢?

[Headers("User-Agent: Dms-Parts", "Content-Type: application/json")]

  通过上面的方式我们能够配置一组Headers,另外在很多的时候如果Headers里面没有配置Content-Type那么很有可能会返回StatusCode=415 Unsupport Media Type这个类型的错误信息,这个在使用的时候需要注意。

以上就是如何在Asp.Net Core中集成Refit的详细内容,更多关于Asp.Net Core中集成Refit的资料请关注易盾网络其它相关文章!

本文共计2077个文字,预计阅读时间需要9分钟。

如何在Asp.Net Core项目中成功集成并使用Refit进行API调用?

目录+一+常规创建方式+1.1+注入IHttpClientFactory对象+1.2+配置HttpClient的BaseAddress+1.3+HttpClient进行数据的发送和接收+1.4+总结+二+使用Refit来创建HttpClient对象+2.1+引入Refit包+2.2+定义接口+2.3+注入“

目录
  •   一 常规创建方式
    •   1.1 注入IHttpClientFactory对象
    •   1.2 配置HttpClient的BaseAddress  
    •   1.3 HttpClient进行数据的发送和接收
    •   1.4 总结
  •   二 使用Refit来创建HttpClient对象
    •   2.1 引入Refit包
    •   2.2 定义接口
    •   2.3 注入接口并使用接口中的方法
    •   2.4 在Startup中配置基础配置信息
    •   2.5 注意事项

  在很多时候我们在不同的服务之间需要通过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 _blob-storage/", "DcsParts": "dcs-parts/", "DmsAfterSales": "dms-after-sales/" }

  有了这些我们就能够具备创建一个HttpClient对象的条件了,后面我们来看看我们怎么使用这个HttpClient进行发送和接收数据。

  1.3 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); }

  在上面的代码中我们模拟了一个Post请求,请求完成以后我们再使用ReadAsAsync的方法来异步接收另外一个域中的数据,然后我们根据返回的StatusCode来抛出不同的错误提示,并记录相关的日志信息并返回最终Post请求的结果,进而完成整个过程,在这个中间我们发送请求的时候需要注意一下内容:1 最终的完整版地址=BaseAddress+RelativeAddress,基地址是在appsetting.json中进行配置的,RelativeAddress是我们请求不同域的时候的相对地址,这个需要我们根据实际的业务来进行配置。2 请求的对象是我们将数据对象序列化成json后的结果,这两点需要特别注意。

  1.4 总结

  通过上面的讲述我们知道了如何完整的创建HttpClient以及通过创建的HttpClient如何收发数据,但同时我们也发现了通过上面的方式我们的缺点:如果一个业务中有大量的这种跨域请求整个代码显得非常臃肿并且由于不同开发人员的认知不同最终导致很容易出问题,那么我们是否有办法能够去解决上面的问题呢?Refit库的出现正好解决了这个问题,Refit通过这种申明式的方式能够很大程度上让代码更加简练明了而且提供了更加丰富的功能。

如何在Asp.Net Core项目中成功集成并使用Refit进行API调用?

  二 使用Refit来创建HttpClient对象

  2.1 引入Refit包

  在我们的项目中我们可以通过 <PackageReference Include="Refit" Version="XXX" />来快速引用Refit包,引用的方式这里便不再赘述。

  2.2 定义接口

  我们将我们业务中涉及到的方法定义在一个接口中,就像下面这样。

public interface IDmsAfterSalesApi { [Headers("User-Agent: Dms-Parts")] [Post("/internal/api/v1/customerAccounts/update")] Task<ResponseBody> UpdateCustomerAmount([Body]PartRetailSettlementModel input); [Headers("User-Agent: Dms-Parts")] [Post("/internal/api/v1/repairShortagePart/checkCustomerAccount")] Task<RepairShortagePartResponseBody> RepairShortagePartCheckCustomerAccount([Body]RepairShortagePartModel input); [Headers("User-Agent: Dms-Parts")] [Post("/internal/api/v1/vehiclesAndMemberCode/forCoupons")] Task<GetMemberCodeBrandCodeForVehicleBody> GetMemberCodeBrandCodeForVehicle(Guid vehicleId); }

  2.3 注入接口并使用接口中的方法

public class DmsAfterSalesClientService : DomainService { private readonly IDmsAfterSalesApi _api; private readonly ILogger<DcsPartClientService> _logger; private const string From = "Dms After Sales"; public DmsAfterSalesClientService(IDmsAfterSalesApi api, ILogger<DcsPartClientService> logger) { _api = api; _logger = logger; } private async Task<Exception> WrapException(ApiException exception) { if (exception.StatusCode == System.Net.HttpStatusCode.BadRequest) { var receivedBody = await exception.GetContentAsAsync<ResponseBody>(); return new ValidationException($"业务校验失败,{receivedBody.Message} ({From})", exception); } else { _logger.LogWarning(exception, "Call Dms After Sales API failed"); return new ApplicationException($"内部调用失败,{exception.Message} ({exception.StatusCode}) ({From})", exception); } } private Exception WrapException(HttpRequestException exception) { _logger.LogWarning(exception, "Call Dms After Sales API failed"); return new ApplicationException($"内部调用失败,{exception.Message} ({From})", exception); } public async Task UpdateCustomerAmount([Body] PartRetailSettlementModel input) { try { await _api.UpdateCustomerAmount(input); } catch (ApiException ex) { throw await WrapException(ex); } catch (HttpRequestException ex) { throw WrapException(ex); } } public async Task<decimal> RepairShortagePartCheckCustomerAccount([Body] RepairShortagePartModel input) { try { var result = await _api.RepairShortagePartCheckCustomerAccount(input); return result.Payload.BalanceAmount; } catch (ApiException ex) { throw await WrapException(ex); } catch (HttpRequestException ex) { throw WrapException(ex); } } public async Task<GetMemberCodeBrandCodeForVehicleOutput> GetMemberCodeBrandCodeForVehicle([Body]Guid vehicleId) { try { var result = await _api.GetMemberCodeBrandCodeForVehicle(vehicleId); return result.Payload; } catch (ApiException ex) { throw await WrapException(ex); } catch (HttpRequestException ex) { throw WrapException(ex); } } }

  在上面接口中定义好这个方法以后我们就可以直接在我们的领域类中引入这个接口IDmsAfterSalesApi ,然后就直接使用这个接口中的方法,讲到这里便有疑问,这个接口的实现到底在哪里?这里当我们定义好接口然后点击里面的方法转到实现的时候我们发现里面会转到一个叫做RefitStubs.g.cs的类中,然后自动的生成下面的方法。

/// <inheritdoc /> [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [Preserve] [global::System.Reflection.Obfuscation(Exclude=true)] partial class AutoGeneratedIDmsAfterSalesApi : IDmsAfterSalesApi { /// <inheritdoc /> public HttpClient Client { get; protected set; } readonly IRequestBuilder requestBuilder; /// <inheritdoc /> public AutoGeneratedIDmsAfterSalesApi(HttpClient client, IRequestBuilder requestBuilder) { Client = client; this.requestBuilder = requestBuilder; } /// <inheritdoc /> Task<ResponseBody> IDmsAfterSalesApi.UpdateCustomerAmount(PartRetailSettlementModel input) { var arguments = new object[] { input }; var func = requestBuilder.BuildRestResultFuncForMethod("UpdateCustomerAmount", new Type[] { typeof(PartRetailSettlementModel) }); return (Task<ResponseBody>)func(Client, arguments); } /// <inheritdoc /> Task<RepairShortagePartResponseBody> IDmsAfterSalesApi.RepairShortagePartCheckCustomerAccount(RepairShortagePartModel input) { var arguments = new object[] { input }; var func = requestBuilder.BuildRestResultFuncForMethod("RepairShortagePartCheckCustomerAccount", new Type[] { typeof(RepairShortagePartModel) }); return (Task<RepairShortagePartResponseBody>)func(Client, arguments); } /// <inheritdoc /> Task<GetMemberCodeBrandCodeForVehicleBody> IDmsAfterSalesApi.GetMemberCodeBrandCodeForVehicle(Guid vehicleId) { var arguments = new object[] { vehicleId }; var func = requestBuilder.BuildRestResultFuncForMethod("GetMemberCodeBrandCodeForVehicle", new Type[] { typeof(Guid) }); return (Task<GetMemberCodeBrandCodeForVehicleBody>)func(Client, arguments); } }  

  这里面的核心是调用一个BuildRestResultFuncForMethod的方法,后面我们再来分析这里面到底是怎么实现的,这里我们首先把这整个使用流程说完,之前我们说过Refit的很多配置都是通过标签的方式来注入进去的,这里包括请求类型、相对请求地址,那么我们的默认超时时间和BaseAddress到底是怎样来配置的呢?下面我们就来重点讲述。

  2.4 在Startup中配置基础配置信息

public IServiceProvider ConfigureServices(IServiceCollection services) { //refit dms after sales服务 services.AddRefitClient<IDmsAfterSalesApi>() .ConfigureHttpClient(c => { c.BaseAddress = new Uri(_appConfiguration["DependencyServices:DmsAfterSales"]); c.Timeout = TimeSpan.FromMilliseconds(_appConfiguration.GetValue<int>("AppSettings:ServiceTimeOutMs")); }); }

  这里我们看到通过一个AddRefitClient方法我们就能够去配置我们的基础信息,讲到这里我们是不是对整个过程都有一个清楚的认识呢?通过上下两种方式的对比,相信你对整个Refit的使用都有自己的理解。

  2.5 注意事项

  由于我们的Headers经常需要我们去配置一组数据,那么我们应该怎么配置多个项呢?

[Headers("User-Agent: Dms-Parts", "Content-Type: application/json")]

  通过上面的方式我们能够配置一组Headers,另外在很多的时候如果Headers里面没有配置Content-Type那么很有可能会返回StatusCode=415 Unsupport Media Type这个类型的错误信息,这个在使用的时候需要注意。

以上就是如何在Asp.Net Core中集成Refit的详细内容,更多关于Asp.Net Core中集成Refit的资料请关注易盾网络其它相关文章!