You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
11 KiB

using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using X1.DynamicClientCore.Models;
namespace X1.DynamicClientCore.Core
{
/// <summary>
/// DynamicHttpClient 核心执行部分
/// 包含核心的HTTP请求执行逻辑
/// </summary>
public partial class DynamicHttpClient
{
/// <summary>
/// 执行HTTP请求的统一方法
/// </summary>
private async Task<T?> ExecuteRequestAsync<T>(string serviceName, string endpoint, HttpMethod method,
object? data, RequestOptions? options, CancellationToken cancellationToken = default)
{
_logger.LogDebug("开始执行异步请求: {ServiceName}:{Endpoint}, 方法: {Method}", serviceName, endpoint, method);
int requestTimeout = 0; // 声明超时变量,供异常处理使用
try
{
// 1. 获取服务端点
_logger.LogDebug("正在获取服务端点: {ServiceName}", serviceName);
var serviceEndpoint = _endpointManager.GetEndpoint(serviceName);
if (serviceEndpoint == null)
{
_logger.LogWarning("服务端点未找到: {ServiceName}", serviceName);
throw new DynamicHttpClientException(
$"服务 '{serviceName}' 未找到",
DynamicHttpClientExceptionType.ServiceNotFound,
serviceName,
endpoint);
}
if (!serviceEndpoint.Enabled)
{
_logger.LogWarning("服务端点已禁用: {ServiceName}", serviceName);
throw new DynamicHttpClientException(
$"服务 '{serviceName}' 已禁用",
DynamicHttpClientExceptionType.ServiceDisabled,
serviceName,
endpoint);
}
_logger.LogDebug("服务端点获取成功: {ServiceName}, URL: {FullUrl}, 超时: {Timeout}s",
serviceName, serviceEndpoint.GetFullUrl(), serviceEndpoint.Timeout);
// 2. 创建HTTP客户端
_logger.LogDebug("正在创建HTTP客户端");
var httpClient = _httpClientFactory.CreateClient();
requestTimeout = options?.Timeout ?? serviceEndpoint.Timeout;
httpClient.Timeout = TimeSpan.FromSeconds(requestTimeout);
_logger.LogDebug("HTTP客户端创建完成,超时设置: {Timeout}s", requestTimeout);
// 3. 构建请求URL
var url = $"{serviceEndpoint.GetFullUrl()}/{endpoint.TrimStart('/')}";
_logger.LogDebug("构建请求URL: {Url}", url);
var request = new HttpRequestMessage(method, url);
// 4. 添加请求头
if (options?.Headers != null)
{
_logger.LogDebug("添加自定义请求头,数量: {HeaderCount}", options.Headers.Count);
foreach (var header in options.Headers)
{
request.Headers.Add(header.Key, header.Value);
_logger.LogDebug("添加请求头: {Key} = {Value}", header.Key, header.Value);
}
}
else
{
// 添加默认的JSON请求头
request.Headers.Add("Accept", "application/json");
_logger.LogDebug("添加默认JSON请求头: Accept = application/json");
}
// 5. 添加请求体
if (data != null && (method == HttpMethod.Post || method == HttpMethod.Put))
{
_logger.LogDebug("准备序列化请求数据,数据类型: {DataType}", data.GetType().Name);
try
{
var json = JsonConvert.SerializeObject(data);
_logger.LogDebug("请求数据序列化成功,长度: {JsonLength} 字符", json.Length);
request.Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
_logger.LogDebug("请求体设置完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "请求数据序列化失败: {ServiceName}:{Endpoint}", serviceName, endpoint);
throw new DynamicHttpClientException(
"请求数据序列化失败",
DynamicHttpClientExceptionType.SerializationError,
serviceName,
endpoint,
innerException: ex);
}
}
else
{
_logger.LogDebug("无请求体数据");
}
// 6. 获取熔断器并执行请求
HttpResponseMessage response;
if (options?.EnableCircuitBreaker == true)
{
_logger.LogDebug("启用熔断器保护");
var circuitBreaker = _circuitBreakerManager.GetOrCreateCircuitBreaker(
serviceEndpoint.Name, options?.CircuitBreaker);
_logger.LogDebug("熔断器获取成功: {ServiceName}", serviceEndpoint.Name);
_logger.LogInformation("发送请求(带熔断器): {Method} {Url}", method, url);
response = await circuitBreaker.ExecuteAsync(async () => await httpClient.SendAsync(request, cancellationToken));
}
else
{
_logger.LogDebug("跳过熔断器保护");
_logger.LogInformation("发送请求(无熔断器): {Method} {Url}", method, url);
response = await httpClient.SendAsync(request, cancellationToken);
}
_logger.LogDebug("收到响应: {StatusCode} {ReasonPhrase}", response.StatusCode, response.ReasonPhrase);
if (response.IsSuccessStatusCode)
{
_logger.LogDebug("开始读取响应内容");
var content = await response.Content.ReadAsStringAsync(cancellationToken);
_logger.LogDebug("响应内容读取完成,长度: {ContentLength} 字符", content.Length);
_logger.LogInformation("请求成功: {StatusCode}", response.StatusCode);
if (typeof(T) == typeof(string))
{
_logger.LogDebug("返回字符串类型响应");
return (T)(object)content;
}
_logger.LogDebug("开始反序列化响应数据,目标类型: {TargetType}", typeof(T).Name);
try
{
var result = JsonConvert.DeserializeObject<T>(content);
_logger.LogDebug("响应数据反序列化成功");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "响应数据反序列化失败: {ServiceName}:{Endpoint}, 目标类型: {TargetType}",
serviceName, endpoint, typeof(T).Name);
throw new DynamicHttpClientException(
"响应数据反序列化失败",
DynamicHttpClientExceptionType.SerializationError,
serviceName,
endpoint,
(int)response.StatusCode,
ex);
}
}
else
{
_logger.LogError("请求失败: {StatusCode} {ReasonPhrase}, URL: {Url}",
response.StatusCode, response.ReasonPhrase, url);
throw new DynamicHttpClientException(
$"HTTP请求失败: {response.StatusCode} {response.ReasonPhrase}",
DynamicHttpClientExceptionType.HttpRequestFailed,
serviceName,
endpoint,
(int)response.StatusCode);
}
}
catch (DynamicHttpClientException ex)
{
// 记录自定义异常,然后重新抛出
_logger.LogError(ex, "动态HTTP客户端异步异常: {ServiceName}:{Endpoint}, 类型: {ExceptionType}, 消息: {Message}",
serviceName, endpoint, ex.ExceptionType, ex.Message);
throw;
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
// 超时异常
_logger.LogWarning("异步请求超时: {ServiceName}:{Endpoint}, 超时时间: {Timeout}s",
serviceName, endpoint, requestTimeout);
throw new DynamicHttpClientException(
"请求超时",
DynamicHttpClientExceptionType.Timeout,
serviceName,
endpoint,
innerException: ex);
}
catch (OperationCanceledException ex)
{
// 请求被取消
_logger.LogInformation("异步请求被取消: {ServiceName}:{Endpoint}", serviceName, endpoint);
throw new DynamicHttpClientException(
"请求被取消",
DynamicHttpClientExceptionType.RequestCanceled,
serviceName,
endpoint,
innerException: ex);
}
catch (HttpRequestException ex)
{
// HTTP请求异常
_logger.LogError(ex, "HTTP异步请求异常: {ServiceName}:{Endpoint}, 消息: {Message}",
serviceName, endpoint, ex.Message);
throw new DynamicHttpClientException(
"网络请求失败",
DynamicHttpClientExceptionType.NetworkError,
serviceName,
endpoint,
innerException: ex);
}
catch (Exception ex)
{
// 其他未知异常
_logger.LogError(ex, "异步请求未知异常: {ServiceName}:{Endpoint}, 异常类型: {ExceptionType}, 消息: {Message}",
serviceName, endpoint, ex.GetType().Name, ex.Message);
throw new DynamicHttpClientException(
"请求执行失败",
DynamicHttpClientExceptionType.Unknown,
serviceName,
endpoint,
innerException: ex);
}
finally
{
_logger.LogDebug("异步请求执行完成: {ServiceName}:{Endpoint}", serviceName, endpoint);
}
}
}
}