6.24DelegatingHandler 请求拦截
DelegatingHandler 是 C# 中 HttpClient 类的一个重要组成部分,它允许你以一种链式的方式处理 HTTP 请求和响应。DelegatingHandler 是一个抽象类,通常用于创建自定义的消息处理器,这些处理器可以被插入到 HTTP 消息处理管道中。通过继承 DelegatingHandle
DelegatingHandler 请求处理委托(拦截)#
DelegatingHandler 是 C# 中 HttpClient 类的一个重要组成部分,它允许你以一种链式的方式处理 HTTP 请求和响应。DelegatingHandler 是一个抽象类,通常用于创建自定义的消息处理器,这些处理器可以被插入到 HTTP 消息处理管道中。通过继承 DelegatingHandler 并重写其 Send 和 SendAsync 方法,你可以实现自定义的行为,比如添加请求头、日志记录、身份验证、错误处理等。
简单来说,DelegatingHandler 可以被视为一个拦截 HTTP 远程请求的“中间件”。
DelegatingHandler 应用场景#
- 请求前处理:在请求发送到服务器之前,可以对请求进行修改或增强,例如添加认证信息、设置特定的请求头等。
- 响应后处理:在从服务器接收到响应之后但在最终用户看到结果之前,可以对响应进行处理,如解压、解密、缓存响应等。
- 错误处理:统一处理所有
HTTP请求可能发生的异常,提供一致的错误处理机制。 - 日志记录:记录请求和响应的信息,便于调试和监控。
框架内置的 ProfilerDelegatingHandler 是一个请求分析工具,它通过实现 DelegatingHandler 接口来实现其功能。您可以点击此处查看源码,以深入了解其实现细节。
自定义 DelegatingHandler#
以下是一个简单的 DelegatingHandler 示例,展示了如何在请求发送前添加自定义请求头,并在响应接收后记录响应状态码:
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.cs 或 Startup.cs 文件中注册 CustomHandler:
// 注册 CustomHandler 为服务services.TryAddSingleton<CustomHandler>();// 为默认 HttpClient 客户端启用 CustomHandlerservices.AddHttpClient() .AddHttpMessageHandler<CustomHandler>();// 若为特定命名的 HttpClient 客户端启用,可如下配置// services.AddHttpClient("weixin")// .AddHttpMessageHandler<CustomHandler>();.AddHttpMessageHandler 方法支持多次调用,以添加多个处理器。例如:
services.AddHttpClient(string.Empty) .AddHttpMessageHandler<CustomHandler1>() .AddHttpMessageHandler<CustomHandler2>() .AddHttpMessageHandler<CustomHandler3>();注意:处理器的执行顺序为注册顺序,即先注册的处理器先执行。
实现自动刷新授权 Token#
在与第三方 API 接口对接时,通常需要在请求头中携带授权 Token。由于 Token 具有时效性,开发者需要定期刷新 Token。以下示例展示了如何通过 DelegatingHandler 实现自动刷新 Token 的逻辑。当响应返回 401 状态码时,系统会自动重新获取授权 Token 并更新请求头。
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.cs 或 Startup.cs 文件中注册 AuthorizationDelegatingHandler:
// 注册 AuthorizationDelegatingHandler 为服务services.TryAddSingleton<AuthorizationDelegatingHandler>();// 为默认 HttpClient 客户端启用 AuthorizationDelegatingHandlerservices.AddHttpClient() .AddHttpMessageHandler<AuthorizationDelegatingHandler>();// 若为特定命名的 HttpClient 客户端启用,可如下配置// services.AddHttpClient("weixin")// .AddHttpMessageHandler<AuthorizationDelegatingHandler>();通过上述代码,我们实现了一个自动刷新 Token 的机制。当 Token 过期时,系统会自动获取新的 Token 并重试请求,从而确保与第三方 API 的持续有效通信。