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 static class ResourceHttpUtils
|
{
|
/// <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)
|
{
|
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>
|
/// 发送请求
|
/// </summary>
|
/// <typeparam name="TRequest"></typeparam>
|
/// <typeparam name="TResponse"></typeparam>
|
/// <param name="request"></param>
|
/// <param name="provider"></param>
|
/// <returns></returns>
|
public static async Task<TResponse> SendHttpAsync<TRequest, TResponse>(
|
this TRequest request,
|
EnumResourceHttpProvider? provider = null)
|
{
|
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;
|
}
|
|
/// <summary>
|
/// 获取请求方式
|
/// </summary>
|
/// <param name="method"></param>
|
/// <returns></returns>
|
public static HttpMethod GetHttpMethod(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, "不支持的请求类型");
|
}
|
}
|
|
/// <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>
|
/// 获取健康服务域名
|
/// </summary>
|
/// <param name="serviceName"></param>
|
/// <returns></returns>
|
public static async Task<string> GetHealthyServiceDomain(string serviceName)
|
{
|
var env = App.GetConfig<string>("Environment");
|
serviceName = $"{env}_{serviceName}";
|
|
var queryResult = await App.GetRequiredService<IConsulClient>().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];
|
}
|
|
}
|
}
|