HtmlToPdf/mvp/HtmlToPdfService.Core/Services/CallbackService.cs
2025-12-11 23:35:52 +08:00

125 lines
4.1 KiB
C#
Raw 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 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;
/// <summary>
/// 回调服务实现
/// </summary>
public class CallbackService : ICallbackService
{
private readonly CallbackOptions _options;
private readonly ILogger<CallbackService> _logger;
private readonly IHttpClientFactory _httpClientFactory;
public CallbackService(
IOptions<PdfServiceOptions> options,
ILogger<CallbackService> logger,
IHttpClientFactory httpClientFactory)
{
_options = options.Value.Callback;
_logger = logger;
_httpClientFactory = httpClientFactory;
}
/// <summary>
/// 发送回调Fire-and-Forget 模式)
/// </summary>
public async Task SendCallbackAsync(
string callbackUrl,
CallbackPayload payload,
Dictionary<string, string>? 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);
}
/// <summary>
/// 实际发送回调
/// </summary>
private async Task SendCallbackInternalAsync(
string callbackUrl,
CallbackPayload payload,
Dictionary<string, string>? 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);
}
}
}