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 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 static class ResourceHttpUtils { public static async Task SendHttpAsync(this object request, string serviceName, string route, EnumResourceMethod method, EnumResourceHttpProvider? provider = null) { serviceName = App.GetConfig($"{serviceName}:ServiceName"); var url = await GetUrl(serviceName, route); var builder = HttpRequestBuilder.Create(method.GetMethod(), url); if (method == EnumResourceMethod.Get) builder = builder.WithQueryParameters(request); else builder = builder.SetJsonContent(request); 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; } public static async Task SendHttpAsync(this TRequest request, EnumResourceHttpProvider? provider = null) { var requestType = typeof(TRequest); var resourceAttribute = requestType.GetCustomAttribute(); if (resourceAttribute == null) throw Oops.Oh(EnumErrorCodeType.s400, "缺失资源特性"); var controller = resourceAttribute.Controllers.FirstOrDefault(); var resourceControllerAttribute = controller.GetCustomAttribute(); 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().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(); return response; } public static HttpMethod GetMethod(this EnumResourceMethod method) { 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 static async Task GetUrl(string serviceName, string route) { var domain = await GetHealthyServiceDomain(serviceName); return $"{domain}{route}"; } /// /// 获取健康服务域名 /// /// /// public static async Task GetHealthyServiceDomain(string serviceName) { var env = App.GetConfig("Environment"); serviceName = $"{env}_{serviceName}"; var queryResult = await App.GetRequiredService().Health.Service(serviceName, null, true); if (queryResult.StatusCode != System.Net.HttpStatusCode.OK) throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{serviceName}"); var domains = queryResult.Response .Select(s => $"http://{s.Service.Address}:{s.Service.Port}") .ToList(); if (domains.IsNull()) throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{serviceName}"); // 轮询选择实例 int randomIndex = new Random().Next(domains.Count); return domains[randomIndex]; } } }