sunpengfei
7 天以前 a2efd6c3bdbea77ef13205f4102cae774a233041
FlexJobApi.Core/Utils/ResourceUtils/ResourceHttpUtils.cs
@@ -1,77 +1,149 @@
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> 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}";
@@ -82,12 +154,12 @@
        /// </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}");