using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using HtmlToPdfService.Core.Models;
using HtmlToPdfService.Core.Options;
namespace HtmlToPdfService.Core.Services;
///
/// 回调服务实现
///
public class CallbackService : ICallbackService
{
private readonly CallbackOptions _options;
private readonly ILogger _logger;
private readonly IHttpClientFactory _httpClientFactory;
public CallbackService(
IOptions options,
ILogger logger,
IHttpClientFactory httpClientFactory)
{
_options = options.Value.Callback;
_logger = logger;
_httpClientFactory = httpClientFactory;
}
///
/// 发送回调(Fire-and-Forget 模式)
///
public async Task SendCallbackAsync(
string callbackUrl,
CallbackPayload payload,
Dictionary? customHeaders = null,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(callbackUrl))
{
_logger.LogDebug("回调 URL 为空,跳过回调");
return;
}
if (!_options.Enabled)
{
_logger.LogDebug("回调功能已禁用,跳过回调");
return;
}
// Fire-and-Forget:不等待回调完成
_ = Task.Run(async () =>
{
try
{
await SendCallbackInternalAsync(callbackUrl, payload, customHeaders, cancellationToken);
}
catch (Exception ex)
{
// 只记录日志,不抛出异常
_logger.LogError(ex, "回调发送失败: {Url}, RequestId: {RequestId}",
callbackUrl, payload.RequestId);
}
}, cancellationToken);
_logger.LogInformation("回调已触发(异步): {Url}, RequestId: {RequestId}",
callbackUrl, payload.RequestId);
}
///
/// 实际发送回调
///
private async Task SendCallbackInternalAsync(
string callbackUrl,
CallbackPayload payload,
Dictionary? customHeaders,
CancellationToken cancellationToken)
{
var httpClient = _httpClientFactory.CreateClient("CallbackClient");
httpClient.Timeout = TimeSpan.FromMilliseconds(_options.Timeout);
var request = new HttpRequestMessage(HttpMethod.Post, callbackUrl);
// 添加全局配置的 Headers
foreach (var header in _options.CustomHeaders)
{
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
// 添加请求级的自定义 Headers(优先级更高)
if (customHeaders != null)
{
foreach (var header in customHeaders)
{
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
// 序列化 Payload
var jsonContent = JsonSerializer.Serialize(payload, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
});
request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
_logger.LogDebug("发送回调请求: {Url}, Payload: {Payload}", callbackUrl, jsonContent);
var response = await httpClient.SendAsync(request, cancellationToken);
if (response.IsSuccessStatusCode)
{
_logger.LogInformation("回调发送成功: {Url}, StatusCode: {StatusCode}, RequestId: {RequestId}",
callbackUrl, (int)response.StatusCode, payload.RequestId);
}
else
{
var responseBody = await response.Content.ReadAsStringAsync(cancellationToken);
_logger.LogWarning("回调返回非成功状态码: {Url}, StatusCode: {StatusCode}, Response: {Response}, RequestId: {RequestId}",
callbackUrl, (int)response.StatusCode, responseBody, payload.RequestId);
}
}
}