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); } } }