using Microsoft.Extensions.Logging; using Nacos.V2; using Nacos.V2.Common; using Polly; using Polly.Retry; using Refit; using System; using System.Text.Json; using System.Threading.Tasks; namespace Microservice.Common { public class ServiceClient : IServiceClient { private readonly INacosNamingService _nacosNamingService; private readonly ILogger _logger; private readonly AsyncRetryPolicy _retryPolicy; public ServiceClient(INacosNamingService nacosNamingService, ILogger logger) { _nacosNamingService = nacosNamingService; _logger = logger; // 配置重试策略 _retryPolicy = Policy .Handle() .WaitAndRetryAsync( retryCount: 3, sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)) ); } public async Task GetAsync(string serviceName, string endpoint, object queryParams = null) { try { var result = await SendRequestAsync(serviceName, endpoint, "GET", null, queryParams); return result; } catch (Exception) { throw; } } public async Task PostAsync(string serviceName, string endpoint, object data) { return await SendRequestAsync(serviceName, endpoint, "POST", data); } public async Task PutAsync(string serviceName, string endpoint, object data) { return await SendRequestAsync(serviceName, endpoint, "PUT", data); } public async Task DeleteAsync(string serviceName, string endpoint) { return await SendRequestAsync(serviceName, endpoint, "DELETE"); } private async Task SendRequestAsync(string serviceName, string endpoint, string method, object data = null, object queryParams = null) { try { // 从Nacos获取服务实例 var instance = await _nacosNamingService.SelectOneHealthyInstance(serviceName); if (instance == null) { throw new Exception($"未找到服务 {serviceName} 的可用实例"); } // 构建服务基础URL var baseUrl = $"http://{instance.Ip}:{instance.Port}"; // 创建Refit服务实例 var serviceApi = RestService.For(baseUrl); // 确保endpoint不包含前导的斜杠,因为IServiceApi中的路径模板已经包含了一个斜杠 if (!string.IsNullOrEmpty(endpoint)) { // 移除所有前导的'/' endpoint = endpoint.TrimStart('/'); } // 使用重试策略 TResponse result = default; await _retryPolicy.ExecuteAsync(async () => { ApiResponse apiResponse; // 根据HTTP方法调用不同的API switch (method.ToUpper()) { case "GET": apiResponse = await serviceApi.GetAsync(endpoint); break; case "POST": apiResponse = await serviceApi.PostAsync(endpoint, data); break; case "PUT": apiResponse = await serviceApi.PutAsync(endpoint, data); break; case "DELETE": apiResponse = await serviceApi.DeleteAsync(endpoint); break; default: throw new NotSupportedException($"不支持的HTTP方法: {method}"); } // 检查响应状态码 if (apiResponse.StatusCode >= 200 && apiResponse.StatusCode < 300) { // 成功响应,返回数据 result = apiResponse.Data; } else { // 失败响应,抛出异常 throw new ApiException(apiResponse.StatusCode, apiResponse.Message); } }); return result; } catch (ApiException) { // 重新抛出 ApiException throw; } catch (Exception) { throw; } } } }