DelegatingHandler是Asp.Net webAPI中位于HTTP请求处理管道里的重要消息处理器,它继承自HttpMessageHandler,主要用于在请求到达控制器之前或者响应返回客户端之前,对HTTP消息进行拦截和处理,能够实现统一的请求校验、日志记录、参数修改等通用功能,避免在每个接口中重复编写相同逻辑。

DelegatingHandler的基本作用
DelegatingHandler的核心价值是作为请求处理管道的中间层,所有进入webAPI的HTTP请求都会先经过注册的DelegatingHandler,处理完成后再传递到下一个处理器,最终到达对应的控制器方法。响应生成后也会按照相反的顺序经过这些DelegatingHandler再返回给客户端。它的主要作用包括:
- 统一拦截所有请求,实现全局的请求头校验、身份认证逻辑
- 记录请求和响应的详细日志,方便问题排查
- 修改请求参数或者响应内容,比如统一添加响应头
- 实现请求的限流、超时控制等通用策略
自定义DelegatingHandler的实现步骤
要使用DelegatingHandler,首先需要自定义一个类继承自DelegatingHandler,然后重写它的SendAsync方法,在该方法中编写自定义的处理逻辑。以下是一个简单的自定义DelegatingHandler示例,实现请求日志的记录:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace WebApiDemo.Handlers
{
// 自定义日志处理DelegatingHandler
public class LogHandler : DelegatingHandler
{
// 重写SendAsync方法处理请求和响应
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// 记录请求信息
Console.WriteLine($"收到请求:{request.Method} {request.RequestUri}");
Console.WriteLine($"请求时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
// 调用下一个处理器处理请求,获取响应
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
// 记录响应信息
Console.WriteLine($"响应状态码:{response.StatusCode}");
Console.WriteLine($"响应时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
return response;
}
}
}
将DelegatingHandler注册到webAPI管道
自定义完成DelegatingHandler之后,需要将其注册到webAPI的请求处理管道中,才能生效。在Asp.Net webAPI中,通常在WebApiConfig类的Register方法中完成注册,具体代码如下:
using System.Web.Http;
using WebApiDemo.Handlers;
namespace WebApiDemo
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// 注册自定义的LogHandler到消息处理器集合
config.MessageHandlers.Add(new LogHandler());
// 其他webAPI配置
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
多个DelegatingHandler的执行顺序
如果注册了多个DelegatingHandler,它们的执行顺序和注册顺序一致:请求阶段按照注册顺序依次执行,响应阶段按照注册的逆序依次执行。比如先注册HandlerA,再注册HandlerB,那么请求会先经过HandlerA再经过HandlerB,响应会先经过HandlerB再经过HandlerA。可以通过以下示例验证:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace WebApiDemo.Handlers
{
// 第一个测试Handler
public class TestHandlerA : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine("TestHandlerA 处理请求");
var response = await base.SendAsync(request, cancellationToken);
Console.WriteLine("TestHandlerA 处理响应");
return response;
}
}
// 第二个测试Handler
public class TestHandlerB : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine("TestHandlerB 处理请求");
var response = await base.SendAsync(request, cancellationToken);
Console.WriteLine("TestHandlerB 处理响应");
return response;
}
}
}
注册时先添加TestHandlerA,再添加TestHandlerB,发起请求后控制台输出顺序为:
TestHandlerA 处理请求
TestHandlerB 处理请求
TestHandlerB 处理响应
TestHandlerA 处理响应
常见使用场景和注意事项
DelegatingHandler在实际开发中有很多实用场景,比如实现简单的API密钥校验:
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace WebApiDemo.Handlers
{
// API密钥校验Handler
public class ApiKeyHandler : DelegatingHandler
{
// 预设的合法API密钥
private const string ValidApiKey = "demo_valid_key_123";
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// 从请求头中获取API密钥
if (!request.Headers.TryGetValues("X-Api-Key", out var apiKeys))
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("缺少API密钥请求头")
};
}
string apiKey = apiKeys.ToString();
if (apiKey != ValidApiKey)
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("API密钥无效")
};
}
// 密钥校验通过,继续处理请求
return await base.SendAsync(request, cancellationToken);
}
}
}
使用DelegatingHandler时需要注意,不要在SendAsync方法中编写过于耗时的逻辑,避免阻塞请求处理管道。如果需要执行耗时操作,建议使用异步方式处理。另外,如果需要在DelegatingHandler中获取请求的内容,需要注意请求内容流只能读取一次,读取后需要重新设置请求内容,避免后续处理器无法读取。
DelegatingHandlerAsp.Net_webAPIC#消息处理器HTTP请求管道修改时间:2026-07-21 08:57:25