WebApi2官網學習記錄--HTTP Message Handlers

Message Handlers是一個接收HTTP Request返回HTTP Response的類,繼承自HttpMessageHandlerapi

一般,一些列的message handler被連接到一塊兒。第一個handler收到http request作一些處理,而後將request傳遞到下一個handler。在某時刻,response被創並返回。這種模式被稱爲delegating hanlder框架

服務端消息處理

在服務端,WebAPI管道使用一些內建的message handlers異步

  • HttpServer 從主機獲取request
  • HttpRoutingDispacher 基於路由分配request
  • HttpControllerDispacher 發送request到WebAPI的controller

能夠在pipline中自定義message handlers,如圖,展現了兩個自定義的handlerasync

自定義 Message Handlers

自定義message handler須要實現System.Net.Http.DelegatingHandler接口,並重載SendAsync方法。ide

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

典型的實現經過一些流程:spa

  1. 處理request message
  2. 調用base.SendAsync將request傳遞到內部的handler(inner handler)
  3. 內部的handler返回一個response message(這步是異步的)
  4. 處理response並返回給調用者

一個簡單的例子:code

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頗有用)blog

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);
         }
     }
相關文章
相關標籤/搜索