zoukankan      html  css  js  c++  java
  • WebApi2官网学习记录--HTTP Message Handlers

    Message Handlers是一个接收HTTP Request返回HTTP Response的类,继承自HttpMessageHandler

    通常,一些列的message handler被链接到一起。第一个handler收到http request做一些处理,然后将request传递到下一个handler。在某时刻,response被创并返回。这种模式被称为delegating hanlder

    服务端消息处理

    在服务端,WebAPI管道使用一些内建的message handlers

    • HttpServer 从主机获取request
    • HttpRoutingDispacher 基于路由分配request
    • HttpControllerDispacher 发送request到WebAPI的controller

    可以在pipline中自定义message handlers,如图,展示了两个自定义的handler

    自定义 Message Handlers

    自定义message handler需要实现System.Net.Http.DelegatingHandler接口,并重载SendAsync方法。

    Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken);
    

    典型的实现通过一些流程:

    1. 处理request message
    2. 调用base.SendAsync将request传递到内部的handler(inner handler)
    3. 内部的handler返回一个response message(这步是异步的)
    4. 处理response并返回给调用者

    一个简单的例子:

    public class MessageHandler1 : DelegatingHandler
    {
        protected async override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Debug.WriteLine("Process request");
            // Call the inner handler.
            var response = await base.SendAsync(request, cancellationToken);
            Debug.WriteLine("Process response");
            return response;
        }
    }
    

    当然,也可以跳过inner handler,直接创建一个response(这种方式对于验证request很有用)

    public class MessageHandler2 : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // Create the response.
            var response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent("Hello!")
            };
    
            // Note: TaskCompletionSource creates a task that does not contain a delegate.
            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(response);   // Also sets the task state to "RanToCompletion"
            return tsc.Task;
        }
    }
    

    添加Handler到Pipeline

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.MessageHandlers.Add(new MessageHandler1());
            config.MessageHandlers.Add(new MessageHandler2());
    
            // Other code not shown...
        }
    }
    

    Message Handler被调用的顺序与添加到MessageHandlers集合的顺序相同,由于是嵌套的response message消息传播的方向正好与此相反。

    对于inner handlers我们不需要设置,WebAPI框架会自动连接。

    Per-Route Message Handlers

    既可以在 HttpConfiguration.MessageHandlers集合中设置Handlers应用到globally范围,也可以在指定路由上添加一个message handler

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "Route1",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            config.Routes.MapHttpRoute(
                name: "Route2",
                routeTemplate: "api2/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional },
                constraints: null,
    			handler: new MessageHandler2()// per-route message handler
            );
    
            config.MessageHandlers.Add(new MessageHandler1());  // global message handler
        }
    }
    

    通过以上配置,如果URI匹配"Route2",请求将被分配到MessageHandler2。如下图所示:

    注意:MessageHandler2会替代默认的HttpControllerDispatcher,匹配"Route2"的request将不能找到对应的controller,可以通过手动建立HttpControllerDispatcher来解决。

    // List of delegating handlers.
    DelegatingHandler[] handlers = new DelegatingHandler[] {
        new MessageHandler3()
    };
    
    // Create a message handler chain with an end-point.
    var routeHandlers = HttpClientFactory.CreatePipeline(
        new HttpControllerDispatcher(config), handlers);
    
    config.Routes.MapHttpRoute(
        name: "Route2",
        routeTemplate: "api2/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional },
        constraints: null,
        handler: routeHandlers
    );
    

    使用Message Handler的例子

    1. 跳过inner handler 直接返回response

      /// <summary>
      /// 跳过inner handler 直接返回response
      /// </summary>
      public class MyMessageHandler2:DelegatingHandler
      {
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
          {
              // Create the response.
              var response = new HttpResponseMessage(HttpStatusCode.OK)
              {
                  Content = new StringContent("Hello!")
              };
      
              // Note: TaskCompletionSource creates a task that does not contain a delegate.
              var tsc = new TaskCompletionSource<HttpResponseMessage>();
              tsc.SetResult(response);   // Also sets the task state to "RanToCompletion"
                                         //  return tsc.Task;
              return base.SendAsync(request,cancellationToken);
          }
      }
      
    2. 重写Request method

       /// <summary>
       /// 重写Request method
       /// </summary>
       public class MethodOverrideHandler:DelegatingHandler
       {
           readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
           const string _header= "X-HTTP-Method-Override";
      
           protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
           {
               if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
               {
                   var method = request.Headers.GetValues(_header).FirstOrDefault();
                   if (_methods.Contains(method, StringComparer.InvariantCulture))
                   {
                       request.Method = new HttpMethod(method);
                   }
               }
               return base.SendAsync(request, cancellationToken);
           }
       }
  • 相关阅读:
    shell学习之杂项
    boot小知识
    记一个数组的问题
    lnmp安装exif扩展
    国内的Git比GitHub快
    重用思想,要有识别出好代码的眼睛,识别出腐朽代码的眼睛
    CSS3之超出隐藏
    如何测量设计图中图片的尺寸,像素
    Linux 软链接操作项目
    微信小程序申请。很蛋疼的流程。
  • 原文地址:https://www.cnblogs.com/goodlucklzq/p/4479498.html
Copyright © 2011-2022 走看看