DelegatingHandler,在web api中进行统一安全验证类DelegatingHandler

DelegatingHandler 是一个抽象类,用于在 ASP.NET Core 中扩展 HttpClient 的功能。它允许开发者通过继承该类并重写 SendAsync 方法,来拦截和处理 HTTP 请求和响应。这在实现日志记录、身份验证、重试逻辑等通用功能时非常有用。
原文链接:https://www.cnblogs.com/lwyu/p/10593727.html

将 HTTP 响应消息的处理委托给另一处理程序(称为“内部处理程序”)的 HTTP 处理程序的类型。

如何理解这句话的意思?

首先我们应知道Asp.Net Web Api 的http消息响应机制,这里我可以解释为:消息管道串联。官方代码指出:public abstract class DelegatingHandler : System.Net.Http.HttpMessageHandler,

而具体实现“管道串联”是通过DelegatingHandler这个类型来完成。

通过以上文档得出疑问

当DelegatingHandler自己负责的消息处理任务完成之后可以委托另一个HttpMessagHandler进行后续的处理。

如果这个被委托的也是一个DelegatingHandler对象,不就可以组成一个委托链了吗?而这个委托链不就是由一个个DelegatingHandler组成的消息处理管道吗?

 以上问题我们可以从程序集 System.Net.Http.dll, v4.0.0.0中得到答案:
复制代码
namespace System.Net.Http
{
    // 摘要: 
    //     被称为内部处理程序的并将 HTTP 响应消息委托给另一处理程序的 HTTP 处理程序的基类型。
    public abstract class DelegatingHandler : HttpMessageHandler
    {
        // 摘要: 
        //     创建 System.Net.Http.DelegatingHandler 类的新实例。
        protected DelegatingHandler();
        //
        // 摘要: 
        //     创建特定内部处理程序的 System.Net.Http.DelegatingHandler 类的新实例。
        //
        // 参数: 
        //   innerHandler:
        //     负责处理 HTTP 响应消息的内部处理程序。
        protected DelegatingHandler(HttpMessageHandler innerHandler);

        // 摘要: 
        //     获取或设置处理 HTTP 响应消息的内部处理程序。
        //
        // 返回结果: 
        //     返回 System.Net.Http.HttpMessageHandler。 HTTP 响应消息的内部处理程序。
        public HttpMessageHandler InnerHandler { get; set; }

        // 摘要: 
        //     释放由 System.Net.Http.DelegatingHandler 使用的非托管资源,并可根据需要释放托管资源。
        //
        // 参数: 
        //   disposing:
        //     如果为 true,则释放托管资源和非托管资源;如果为 false,则仅释放非托管资源。
        protected override void Dispose(bool disposing);
        //
        // 摘要: 
        //     以异步操作发送 HTTP 请求到内部管理器以发送到服务器。
        //
        // 参数: 
        //   request:
        //     要发送到服务器的 HTTP 请求消息。
        //
        //   cancellationToken:
        //     取消操作的取消标记。
        //
        // 返回结果: 
        //     返回 System.Threading.Tasks.Task<TResult>。 表示异步操作的任务对象。
        //
        // 异常: 
        //   System.ArgumentNullException:
        //     request 为 null。
        protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    }
}
复制代码

我们在此可以总结出,如ASP.NET Web API的消息处理管道均由DelegatingHandler组成(位于管道尾端的HttpMessageHandler除外),我们就可以根据其InnerHandler获得对被委托的HttpMessageHandler对象的引用,由此便构成消息处理的链式结构。组成ASP.NET Web API核心框架的消息处理管道,

理论总结的差不多,那么下面我们就对该消息处理委托类进行消息自定义操作,

复制代码
public class RequestMessageDelegatingHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return base.SendAsync(request, cancellationToken).ContinueWith((responseToCompleteTask) =>
            {
                //获取URL参数
                NameValueCollection query = HttpUtility.ParseQueryString(request.RequestUri.Query);
                //获取Post正文数据,比如json文本
                string fRequesContent = request.Content.ReadAsStringAsync().Result;

                //可以做一些其他安全验证工作,比如Token验证,签名验证。
                //可以在需要时自定义HTTP响应消息
                //return SendError("自定义的HTTP响应消息", HttpStatusCode.OK);


                HttpResponseMessage response = responseToCompleteTask.Result;
                HttpError error = null;
                if (response.TryGetContentValue<HttpError>(out error))
                {
                    //添加自定义错误处理
                    //error.Message = "请求失败";
                }

                if (error != null)
                {
                    //记录关键的异常信息
                    QWPlatform.SystemLibrary.LogManager.Logger.Instance.Error("[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "]404错误:请求数据" + error.Message);
                    //返回错误信息
                    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.OK)
                    {
                        //封装处理异常信息,返回指定JSON对象
                        Content = new StringContent(new ZLSoft.CHSS.Web.Public.Library.BaseClass.AjaxResult(Common.Base.AjaxResultType.失败, error.Message + "404").CreateResultString()), //Encoding.GetEncoding("UTF-8"), "application/json"
                        ReasonPhrase = "Exception"

                    });
                }
                else
                {
                    return response;
                }
            }, cancellationToken);
        }
    }
复制代码

接下来,我们只需要把当前类注册到 webapiconfig类当中。

复制代码
public class WebAPIConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //跨域配置
            config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
            //  config.MapHttpAttributeRoutes();

            //注册路由映射
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
                );
            config.MessageHandlers.Add(new RequestMessageDelegatingHandler()); 
} }
复制代码

接下里就可以在 RequestMessageDelegatingHandler 中间写好消息处理机制哪里进行统一的安全校验。

创建自定义 DelegatingHandler

要创建自定义的 DelegatingHandler,你需要继承 DelegatingHandler 类并重写 SendAsync 方法。以下是一个简单的示例,展示如何在发送请求之前添加一个自定义头:
 
public class CustomDelegatingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // 在发送请求之前添加自定义头
        request.Headers.Add("X-Custom-Header", "CustomValue");

        // 调用内部处理器发送请求
        var response = await base.SendAsync(request, cancellationToken);

        // 在收到响应后可以进行额外处理
        // 例如,记录响应状态码
        Console.WriteLine($"Response Status Code: {response.StatusCode}");

        return response;
    }
}
 

将自定义 DelegatingHandler 添加到 HttpClient

创建了自定义的 DelegatingHandler 后,需要将其添加到 HttpClient 的处理程序链中。这可以通过 AddHttpMessageHandler 方法完成:
 
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("MyClient")
        .AddHttpMessageHandler<CustomDelegatingHandler>();
}
 

使用场景

DelegatingHandler 可以用于多种场景,包括但不限于:
  • 日志记录:记录请求和响应的详细信息,用于监控和调试。
  • 身份验证:自动附加身份验证令牌,并处理令牌刷新。
  • 重试逻辑:在遇到瞬态错误时,实现请求重试策略。
  • 压缩/解压缩:管理请求正文的压缩和响应正文的解压缩。
  • 自定义头:根据特定需求添加或修改 HTTP 头。

注意事项

  • 生命周期管理:自定义的 DelegatingHandler 应该注册为 transient,而不是 singleton。这是因为 DelegatingHandlerInnerHandler 属性在 IHttpClientFactory 的实现中不能重复使用。
  • 错误处理:在 SendAsync 方法中,确保正确处理异常,避免影响整个请求管道。
通过使用 DelegatingHandler,你可以更灵活地扩展和自定义 HTTP 请求和响应处理逻辑,从而提高代码的可维护性和复用性
posted @ 2025-08-12 18:26  yinghualeihenmei  阅读(23)  评论(0)    收藏  举报