HttpClient自定义拦截器以实现日志记录
集成DelegatingHandler类,实现SendAsync方法即可将自定义逻辑注入到HTTP请求和响应处理管道中。
第一步:实现自定义拦截逻辑
以下拦截器实现了当请求发生异常时,记录异常信息到日志文件的功能
/// <summary>
/// 自定义的 HttpMessageHandler,用于处理 HTTP 请求中的已知异常。
/// - 捕获并记录 HTTP 请求中的异常。
/// - 对非成功状态码的响应进行处理,并抛出自定义的 KnownException。
/// </summary>
/// <param name="logger">用于记录日志的 ILogger 实例。</param>
public class KnownExceptionDelegatingHandler(ILogger<KnownExceptionDelegatingHandler> logger) : DelegatingHandler
{
/// <summary>
/// 重写 SendAsync 方法,拦截 HTTP 请求和响应。
/// </summary>
/// <param name="request">HTTP 请求消息。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>HTTP 响应消息。</returns>
/// <exception cref="KnownException">
/// 当发生异常或响应状态码非成功时,抛出自定义的 KnownException。
/// </exception>
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage message;
try
{
// 调用管道中的下一个处理器,发送 HTTP 请求。
message = await base.SendAsync(request, cancellationToken);
}
catch (Exception e)
{
// 捕获异常并记录日志。
logger.LogError(e, "调用服务出错:{url}, HttpRequestException:{message}",
request.RequestUri,
e.Message);
// 抛出自定义的 KnownException,表示发生了未知错误。
throw new KnownException("未知错误");
}
// 检查响应状态码是否为成功状态码(2xx)。
if (!message.IsSuccessStatusCode)
{
// 尝试从响应内容中反序列化为 ResponseData 对象。
var data = await message.Content.ReadFromJsonAsync<ResponseData>(cancellationToken: cancellationToken);
if (data != null)
{
// 如果反序列化成功,抛出包含详细错误信息的 KnownException。
throw new KnownException(data.Message, data.Code, data.ErrorData.ToArray());
}
else
{
// 如果反序列化失败,抛出包含响应原因的 KnownException。
throw new KnownException(message.ReasonPhrase ?? "未知错误");
}
}
// 如果状态码为成功,返回响应消息。
return message;
}
}
第二步:注册
注册到容器:builder.Services.AddTransient<KnownExceptionDelegatingHandler>();
注册HttpClient:services.AddHttpClient()
添加拦截器到HttpClient管道中:builder.AddHttpMessageHandler<KnownExceptionDelegatingHandler>();
单元测试
[Fact]
public async Task AddKnownExceptionDelegatingHandlerTest()
{
// Arrange
var services = new ServiceCollection();
services.AddTransient<KnownExceptionDelegatingHandler>();
services.AddHttpClient("test")
.AddTransient<KnownExceptionDelegatingHandler>();
var provider = services.BuildServiceProvider();
var httpClientFactory = provider.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient("test");
// Act
var ex = await Assert.ThrowsAsync<KnownException>(() => httpClient.GetAsync("http://localhost/500"));
// Assert
Assert.Equal("未知错误", ex.Message);
}

浙公网安备 33010602011771号