Mico.Demo/Microservice.Common/ServiceClient.cs

136 lines
4.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<ServiceClient> _logger;
private readonly AsyncRetryPolicy _retryPolicy;
public ServiceClient(INacosNamingService nacosNamingService, ILogger<ServiceClient> logger)
{
_nacosNamingService = nacosNamingService;
_logger = logger;
// 配置重试策略
_retryPolicy = Policy
.Handle<Exception>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt))
);
}
public async Task<TResponse> GetAsync<TResponse>(string serviceName, string endpoint, object queryParams = null)
{
try
{
var result = await SendRequestAsync<TResponse>(serviceName, endpoint, "GET", null, queryParams);
return result;
}
catch (Exception)
{
throw;
}
}
public async Task<TResponse> PostAsync<TResponse>(string serviceName, string endpoint, object data)
{
return await SendRequestAsync<TResponse>(serviceName, endpoint, "POST", data);
}
public async Task<TResponse> PutAsync<TResponse>(string serviceName, string endpoint, object data)
{
return await SendRequestAsync<TResponse>(serviceName, endpoint, "PUT", data);
}
public async Task<TResponse> DeleteAsync<TResponse>(string serviceName, string endpoint)
{
return await SendRequestAsync<TResponse>(serviceName, endpoint, "DELETE");
}
private async Task<TResponse> SendRequestAsync<TResponse>(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<IServiceApi>(baseUrl);
// 确保endpoint不包含前导的斜杠因为IServiceApi中的路径模板已经包含了一个斜杠
if (!string.IsNullOrEmpty(endpoint))
{
// 移除所有前导的'/'
endpoint = endpoint.TrimStart('/');
}
// 使用重试策略
TResponse result = default;
await _retryPolicy.ExecuteAsync(async () =>
{
ApiResponse<TResponse> apiResponse;
// 根据HTTP方法调用不同的API
switch (method.ToUpper())
{
case "GET":
apiResponse = await serviceApi.GetAsync<TResponse>(endpoint);
break;
case "POST":
apiResponse = await serviceApi.PostAsync<TResponse>(endpoint, data);
break;
case "PUT":
apiResponse = await serviceApi.PutAsync<TResponse>(endpoint, data);
break;
case "DELETE":
apiResponse = await serviceApi.DeleteAsync<TResponse>(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;
}
}
}
}