sunpengfei
2025-08-08 6c0058d15ab61956b806f62a2b576ffd5d723ed9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using Consul;
using Furion;
using Furion.FriendlyException;
using Furion.HttpRemote;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace FlexJobApi.Core
{
    public class ResourceHttpUtils
    {
        private readonly IDistributedCache distributedCache;
        private readonly IHttpRemoteService httpRemoteService;
        private readonly IConsulClient consulClient;
 
        public ResourceHttpUtils(
            IDistributedCache distributedCache,
            IHttpRemoteService httpRemoteService,
            IConsulClient consulClient)
        {
            this.distributedCache = distributedCache;
            this.httpRemoteService = httpRemoteService;
            this.consulClient = consulClient;
        }
 
        /// <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()
        {
            var requestTypeFullName = typeof(TRequest).FullName;
 
            var jsonResourceModels = await distributedCache.GetStringAsync($"ResourceModel|{requestTypeFullName}");
            var resource = jsonResourceModels.JsonTo<ResourceModel>();
            var domain = await GetHealthyServiceDomain(resource);
            var builder = HttpRequestBuilder.Create(resource.GetHttpMethod(), $"{domain}{resource.Route}");
            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);
            return response;
        }
 
        /// <summary>
        /// 获取健康服务域名
        /// </summary>
        /// <param name="resource"></param>
        /// <returns></returns>
        public async Task<string> GetHealthyServiceDomain(ResourceModel resource)
        {
            var queryResult = await consulClient.Health.Service(resource.ServiceName, null, true);
            if (queryResult.StatusCode != System.Net.HttpStatusCode.OK)
                throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{resource.Service}");
 
            var domains = queryResult.Response
                .Select(s => $"http://{s.Service.Address}:{s.Service.Port}")
                .ToList();
            if (domains.IsNull())
                throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{resource.Service}");
            // 轮询选择实例
            int randomIndex = new Random().Next(domains.Count);
            return domains[randomIndex];
        }
 
    }
}