| | |
| | | using Azure; |
| | | using Consul; |
| | | using Furion; |
| | | using Furion.DatabaseAccessor; |
| | | using Furion.FriendlyException; |
| | | using Furion.HttpRemote; |
| | | using Microsoft.EntityFrameworkCore; |
| | | using Microsoft.Extensions.Caching.Distributed; |
| | | using RabbitMQ.Client; |
| | | using RTools_NTS.Util; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.ComponentModel.Design; |
| | | using System.Linq; |
| | | using System.Net.Http; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FlexJobApi.Core |
| | | { |
| | | public class ResourceHttpUtils |
| | | public static class ResourceHttpUtils |
| | | { |
| | | private readonly IDistributedCache distributedCache; |
| | | private readonly IHttpRemoteService httpRemoteService; |
| | | private readonly IConsulClient consulClient; |
| | | |
| | | public ResourceHttpUtils( |
| | | IDistributedCache distributedCache, |
| | | IHttpRemoteService httpRemoteService, |
| | | IConsulClient consulClient) |
| | | /// <summary> |
| | | /// 发送请求 |
| | | /// </summary> |
| | | /// <param name="request">请求参数</param> |
| | | /// <param name="serviceName">服务名称</param> |
| | | /// <param name="route">路由</param> |
| | | /// <param name="method">请求方式</param> |
| | | /// <param name="provider">资源提供者</param> |
| | | /// <param name="accessToken">访问令牌</param> |
| | | /// <param name="refreshToken">刷新令牌</param> |
| | | /// <returns></returns> |
| | | public static async Task<string> SendHttpAsync( |
| | | this object request, |
| | | string serviceName, |
| | | string route, |
| | | EnumResourceMethod method, |
| | | EnumResourceHttpProvider? provider = null, |
| | | string accessToken = null, |
| | | string refreshToken = null) |
| | | { |
| | | this.distributedCache = distributedCache; |
| | | this.httpRemoteService = httpRemoteService; |
| | | this.consulClient = consulClient; |
| | | serviceName = App.GetConfig<string>($"{serviceName}:ServiceName"); |
| | | var url = await GetUrl(serviceName, route); |
| | | var builder = HttpRequestBuilder.Create(method.GetHttpMethod(), url); |
| | | |
| | | if (method == EnumResourceMethod.Get) |
| | | builder = builder.WithQueryParameters(request); |
| | | else |
| | | builder = builder.SetJsonContent(request); |
| | | |
| | | if (accessToken.IsNotNull()) |
| | | { |
| | | builder = builder.WithHeader("Authorization", accessToken); |
| | | } |
| | | if (refreshToken.IsNotNull()) |
| | | { |
| | | builder = builder.WithHeader("X-Authorization", refreshToken); |
| | | } |
| | | |
| | | IResourceHttpProvider httpProvider = |
| | | provider == EnumResourceHttpProvider.SystemUser |
| | | ? new SystemUserResourceHttpProvider() |
| | | : provider == EnumResourceHttpProvider.ElectronSignServer |
| | | ? new ElectronSignServerResourceHttpProvider() |
| | | : provider == EnumResourceHttpProvider.ElectronSignServerCustomer |
| | | ? new ElectronSignServerCustomerResourceHttpProvider() |
| | | : new DefaultResourceHttpProvider(); |
| | | var response = await httpProvider.SendAsStringAsync(builder); |
| | | return response; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送HTTP请求 |
| | | /// 发送请求 |
| | | /// </summary> |
| | | /// <typeparam name="TRequest"></typeparam> |
| | | /// <typeparam name="TResponse"></typeparam> |
| | | /// <param name="request"></param> |
| | | /// <param name="provider"></param> |
| | | /// <returns></returns> |
| | | public async Task<TResponse> SendHttpAsync<TRequest, TResponse>( |
| | | TRequest request, |
| | | IResourceHttpProvider provider = null) |
| | | where TRequest : class, new() |
| | | public static async Task<TResponse> SendHttpAsync<TRequest, TResponse>( |
| | | this TRequest request, |
| | | EnumResourceHttpProvider? provider = null) |
| | | { |
| | | var requestTypeFullName = typeof(TRequest).FullName; |
| | | |
| | | var jsonResourceModels = await distributedCache.GetStringAsync($"ResourceModel|{requestTypeFullName}"); |
| | | var resource = jsonResourceModels.JsonTo<ResourceModel>(); |
| | | var url = await GetUrl(resource.ServiceName, resource.Route); |
| | | var builder = HttpRequestBuilder.Create(resource.GetHttpMethod(), url); |
| | | if (resource.Method == EnumResourceMethod.Get) |
| | | builder = builder.WithQueryParameters(request); |
| | | else |
| | | builder = builder.SetJsonContent(request); |
| | | provider = provider ?? new DefaultResourceHttpProvider(); |
| | | builder = provider.AddAuthentication(builder); |
| | | var response = await provider.SendAsAsync<TResponse>(httpRemoteService, builder); |
| | | var requestType = typeof(TRequest); |
| | | var resourceAttribute = requestType.GetCustomAttribute<ResourceAttribute>(); |
| | | if (resourceAttribute == null) throw Oops.Oh(EnumErrorCodeType.s400, "缺失资源特性"); |
| | | var controller = resourceAttribute.Controllers.FirstOrDefault(); |
| | | var resourceControllerAttribute = controller.GetCustomAttribute<EnumResourceController, ResourceControllerAttribute>(); |
| | | if (resourceAttribute == null) throw Oops.Oh(EnumErrorCodeType.s400, "缺失控制器特性"); |
| | | var serviceName = resourceControllerAttribute.Service.ToString(); |
| | | var route = resourceAttribute.Route; |
| | | var method = resourceAttribute.Method; |
| | | var requestXmlDoc = await requestType.GetXmlDocMemberAsync(); |
| | | if (route.IsNull() || method == EnumResourceMethod.None) |
| | | { |
| | | var resource = await Db.GetRepository<Resource>().AsQueryable().AsNoTracking() |
| | | .Where(it => |
| | | it.ServiceName == serviceName |
| | | && it.ControllerName == resourceControllerAttribute.ControllerName |
| | | && it.Code == requestXmlDoc.Name) |
| | | .Select(it => new |
| | | { |
| | | it.Route, |
| | | it.Method |
| | | }) |
| | | .FirstOrDefaultAsync(); |
| | | if (resource == null) throw Oops.Oh(EnumErrorCodeType.s404, "资源"); |
| | | route = resource.Route; |
| | | method = resource.Method; |
| | | } |
| | | var responseJson = await request.SendHttpAsync(serviceName, route, method, provider); |
| | | var response = responseJson.JsonTo<TResponse>(); |
| | | return response; |
| | | } |
| | | |
| | | public async Task<string> SendHttpAsync(Resource resource, string request, IResourceHttpProvider provider = null) |
| | | /// <summary> |
| | | /// 获取请求方式 |
| | | /// </summary> |
| | | /// <param name="method"></param> |
| | | /// <returns></returns> |
| | | public static HttpMethod GetHttpMethod(this EnumResourceMethod method) |
| | | { |
| | | var url = await GetUrl(resource.ServiceName, resource.Route); |
| | | var builder = HttpRequestBuilder.Create(resource.GetHttpMethod(), url); |
| | | if (resource.Method == EnumResourceMethod.Get) |
| | | builder = builder.WithQueryParameters(request); |
| | | else |
| | | builder = builder.SetJsonContent(request); |
| | | provider = provider ?? new DefaultResourceHttpProvider(); |
| | | builder = provider.AddAuthentication(builder); |
| | | var response = await provider.SendAsStringAsync(httpRemoteService, builder); |
| | | return response; |
| | | switch (method) |
| | | { |
| | | case EnumResourceMethod.Get: |
| | | return HttpMethod.Get; |
| | | case EnumResourceMethod.Post: |
| | | return HttpMethod.Post; |
| | | case EnumResourceMethod.Put: |
| | | return HttpMethod.Put; |
| | | case EnumResourceMethod.Delete: |
| | | return HttpMethod.Delete; |
| | | default: |
| | | throw Oops.Oh(EnumErrorCodeType.s400, "不支持的请求类型"); |
| | | } |
| | | } |
| | | |
| | | public async Task<string> SendHttpAsync(EnumResourceService service, HttpMethod method, string route, string request, IResourceHttpProvider provider = null) |
| | | { |
| | | var serviceName = service.GetCustomAttribute<EnumResourceService, ResourceServiceAttribute>().ServiceName; |
| | | var url = await GetUrl(serviceName, route); |
| | | var builder = HttpRequestBuilder.Create(method, url); |
| | | if (method == HttpMethod.Get) |
| | | builder = builder.WithQueryParameters(request); |
| | | else |
| | | builder = builder.SetJsonContent(request); |
| | | provider = provider ?? new DefaultResourceHttpProvider(); |
| | | builder = provider.AddAuthentication(builder); |
| | | var response = await provider.SendAsStringAsync(httpRemoteService, builder); |
| | | return response; |
| | | } |
| | | |
| | | public async Task<string> GetUrl(string serviceName, string route) |
| | | /// <summary> |
| | | /// 获取健康服务地址 |
| | | /// </summary> |
| | | /// <param name="serviceName"></param> |
| | | /// <param name="route"></param> |
| | | /// <returns></returns> |
| | | public static async Task<string> GetUrl(string serviceName, string route) |
| | | { |
| | | var domain = await GetHealthyServiceDomain(serviceName); |
| | | return $"{domain}{route}"; |
| | |
| | | /// </summary> |
| | | /// <param name="serviceName"></param> |
| | | /// <returns></returns> |
| | | public async Task<string> GetHealthyServiceDomain(string serviceName) |
| | | public static async Task<string> GetHealthyServiceDomain(string serviceName) |
| | | { |
| | | var env = App.GetConfig<string>("Environment"); |
| | | serviceName = $"{env}_{serviceName}"; |
| | | |
| | | var queryResult = await consulClient.Health.Service(serviceName, null, true); |
| | | var queryResult = await App.GetRequiredService<IConsulClient>().Health.Service(serviceName, null, true); |
| | | if (queryResult.StatusCode != System.Net.HttpStatusCode.OK) |
| | | throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{serviceName}"); |
| | | |