6.24DelegatingHandler 请求拦截

DelegatingHandler 是 C# 中 HttpClient 类的一个重要组成部分,它允许你以一种链式的方式处理 HTTP 请求和响应。DelegatingHandler 是一个抽象类,通常用于创建自定义的消息处理器,这些处理器可以被插入到 HTTP 消息处理管道中。通过继承 DelegatingHandle

DelegatingHandler 请求处理委托(拦截)#

DelegatingHandler 是 C# 中 HttpClient 类的一个重要组成部分,它允许你以一种链式的方式处理 HTTP 请求和响应。DelegatingHandler 是一个抽象类,通常用于创建自定义的消息处理器,这些处理器可以被插入到 HTTP 消息处理管道中。通过继承 DelegatingHandler 并重写其 SendSendAsync 方法,你可以实现自定义的行为,比如添加请求头、日志记录、身份验证、错误处理等。

简单来说,DelegatingHandler 可以被视为一个拦截 HTTP 远程请求的“中间件”。

DelegatingHandler 应用场景#

  • 请求前处理:在请求发送到服务器之前,可以对请求进行修改或增强,例如添加认证信息、设置特定的请求头等。
  • 响应后处理:在从服务器接收到响应之后但在最终用户看到结果之前,可以对响应进行处理,如解压、解密、缓存响应等。
  • 错误处理:统一处理所有 HTTP 请求可能发生的异常,提供一致的错误处理机制。
  • 日志记录:记录请求和响应的信息,便于调试和监控。

框架内置的 ProfilerDelegatingHandler 是一个请求分析工具,它通过实现 DelegatingHandler 接口来实现其功能。您可以点击此处查看源码,以深入了解其实现细节。

自定义 DelegatingHandler#

以下是一个简单的 DelegatingHandler 示例,展示了如何在请求发送前添加自定义请求头,并在响应接收后记录响应状态码:

csharp
public class CustomHandler : DelegatingHandler{    protected override HttpResponseMessage Send(HttpRequestMessage httpRequestMessage, CancellationToken cancellationToken)    {        // 参考异步 SendAsync 方法        return base.Send(httpRequestMessage, cancellationToken);    }    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)    {        // 请求预处理:添加自定义请求头        request.Headers.Add("Custom-Header", "Value");        // 发送请求并获取响应        var response = await base.SendAsync(request, cancellationToken);        // 响应后处理:记录响应状态码        Console.WriteLine($"Response status code: {response.StatusCode}");        return response;    }}

接下来,在 Program.csStartup.cs 文件中注册 CustomHandler

csharp
// 注册 CustomHandler 为服务services.TryAddSingleton<CustomHandler>();// 为默认 HttpClient 客户端启用 CustomHandlerservices.AddHttpClient()    .AddHttpMessageHandler<CustomHandler>();// 若为特定命名的 HttpClient 客户端启用,可如下配置// services.AddHttpClient("weixin")//     .AddHttpMessageHandler<CustomHandler>();

.AddHttpMessageHandler 方法支持多次调用,以添加多个处理器。例如:

csharp
services.AddHttpClient(string.Empty)    .AddHttpMessageHandler<CustomHandler1>()    .AddHttpMessageHandler<CustomHandler2>()    .AddHttpMessageHandler<CustomHandler3>();

注意:处理器的执行顺序为注册顺序,即先注册的处理器先执行。

实现自动刷新授权 Token#

在与第三方 API 接口对接时,通常需要在请求头中携带授权 Token。由于 Token 具有时效性,开发者需要定期刷新 Token。以下示例展示了如何通过 DelegatingHandler 实现自动刷新 Token 的逻辑。当响应返回 401 状态码时,系统会自动重新获取授权 Token 并更新请求头。

cs
public class AuthorizationDelegatingHandler : DelegatingHandler{    protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)    {        // 参考 SendAsync 代码        return base.Send(request, cancellationToken);    }    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,        CancellationToken cancellationToken)    {        // 克隆原始请求(解决 StreamContent 只能读取一次的问题)        var clonedRequest = await request.CloneAsync(cancellationToken);        // 首次发送请求        var response = await base.SendAsync(clonedRequest, cancellationToken);        // 检测 401 状态码        if (response.StatusCode != HttpStatusCode.Unauthorized)        {            return response;        }        // 刷新 Token        var newToken = await GetNewTokenAsync(); // 实现获取新 Token 的逻辑        // 重新克隆请求并添加新 Token        clonedRequest = await clonedRequest.CloneAsync(cancellationToken);        clonedRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", newToken);        // 重试请求        response = await base.SendAsync(clonedRequest, cancellationToken);        return response;    }    private async Task<string> GetNewTokenAsync()    {        // 这里实现获取新 Token 的逻辑        // 例如:调用身份验证服务获取新的 Token        return "newToken";    }}

接下来,在 Program.csStartup.cs 文件中注册 AuthorizationDelegatingHandler

csharp
// 注册 AuthorizationDelegatingHandler 为服务services.TryAddSingleton<AuthorizationDelegatingHandler>();// 为默认 HttpClient 客户端启用 AuthorizationDelegatingHandlerservices.AddHttpClient()    .AddHttpMessageHandler<AuthorizationDelegatingHandler>();// 若为特定命名的 HttpClient 客户端启用,可如下配置// services.AddHttpClient("weixin")//     .AddHttpMessageHandler<AuthorizationDelegatingHandler>();

通过上述代码,我们实现了一个自动刷新 Token 的机制。当 Token 过期时,系统会自动获取新的 Token 并重试请求,从而确保与第三方 API 的持续有效通信。