Core篇——初探Core的Http請求管道&&Middleware

目錄:

1、Core 處理HTTP請求流程

2、中間件(Middleware)&&處理流程

3、創建自定義中間件&&模擬Core的請求管道

Core 處理HTTP請求流程

Http請求來到之後,會先由WebServer( 例如IIS,Nginx) 拿到然後丟給Kestrel WebServer,再有Kestrel 將Http請求封裝爲HttpContext後傳入給.net core 請求管道(RequestDelegate)。HttpContext經過一系列middleware後返回response給WebServer。

 

中間件(Middleware)&&處理流程

  微軟官方文檔給出的解釋是這樣的:中間件是加載在應用程序管道中以處理和相應請求的組件。其中每個組件都可以 選擇是否可以將請求傳遞給管道中下一個組件;可以在調用管道的下一個組件之前或之後執行。下面是官方文檔給出的一張圖。

  也就是說一個http請求的處理過程爲,經過中間件1的處理邏輯(這個時候可以在中間件1中對httpcontext做一些處理,例如寫入一段內容),調用next()方法,進入到中間件2中,重複以上步驟。最終,所有中間件的處理邏輯的輸出結果都會疊加到HttpResponse中去。

  .net core 中有三種方式調用中間件。在StartUp的Configure方法中,分別可以調用app.Use(),app.Run(),app.Map() 來調用中間件。接下來讓我們來看下:

  app.Use方法有兩個重載形式:

 

第一個方法接收一箇中間件,第二個方法接收一個上下文和一箇中間件。讓我們來分別調用下:

 

 1             app.Use(next =>
 2             {
 3                 return context =>
 4                 { 
 5                     context.Response.WriteAsync("this is middleware1 start...  ");
 6                     return next(context);
 7                 };
 8             });
 9             app.Use(async (context, next) =>
10             {
11                 await context.Response.WriteAsync("this is middleware2 start...   ");
12                 await next();
13             });

  app.Run方法會終止管道,返回HttpResponse。在我們Configure方法中,默認最後一個方法就是app.Run 輸出一句HelloWorld ,如下圖

  Use和Run都比較簡單,不再詳細介紹了。來看一眼程序運行結果:

 

  app.Map 方法用來構建分支管線,它會啓用一個新的ApplicationBuilder。Map根據請求的路徑來匹配分支管線。Map方法也可以根據不同的PathString來匹配多個分支管線或嵌套匹配。

            app.Map("/task", build =>
            {
                build.Run(async (context) =>
                {
                    await context.Response.WriteAsync("this is middleware3 For Map start...  ");
                });
            });
1             app.Map("/map", build =>
2             {
3                 build.Map("/mapTest2", MapHandleTest2);
4                 build.Run(async (context) =>
5                 {
6                     await context.Response.WriteAsync("this is middleware3 For Map start...  ");
7                 });
8             });
9             app.Map("/mapTest1", MapHandleTest1);
 1         private void MapHandleTest1(IApplicationBuilder applicationBuilder)
 2         {
 3             applicationBuilder.Run(async context =>
 4             {
 5                 await context.Response.WriteAsync("this is middleware3HandleTest1 For Map start...  ");
 6             });
 7         }
 8         private void MapHandleTest2(IApplicationBuilder applicationBuilder)
 9         {
10             applicationBuilder.Run(async context =>
11             {
12                 await context.Response.WriteAsync("this is middleware3HandleTest2 For Map start...  ");
13             });
14         }

 

 

  Map還有個特殊的方法,MapWhen, 它接收一個Func<HttpContext, bool>的參數,可以根據Http請求上下文做一些邏輯判斷。然後繼續執行管道

 

1             app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
2                 build =>
3                     build.Run(async context =>
4                     {
5                         var branchVer = context.Request.Query["branch"];
6                         await context.Response.WriteAsync($"Branch used = {branchVer}");
7                     })
8                 );

,這裏再貼張.net core 自帶的中間件

 

 

  

創建自定義中間件&&模擬Core的請求管道

  管道的實現機制由ApplicationBuilderRequestDelegate 組成。RequestDelegate是Middleware的核心,Use方法會將RequestDelegate加入到ApplicationBuilder 中去,最後執行Build方法,把所有RequestDelegate reverse之後挨個執行一遍。

  接下來編寫一個自定義的Middleware。

    public class RequestTestMiddleware
    {
        private readonly RequestDelegate _next;     //中間件核心RequestDelegate,_next 表示執行下一個中間件。
        public RequestTestMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        public Task Invoke(HttpContext context)
        {
            context.Response.WriteAsync("hello this is my RequestTestMiddleware");
            return _next(context);                 //覆蓋delegate 的Inboke方法,將http上下文傳入下一個中間件
        }
    }

    public static class RequestTestMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestTest(this IApplicationBuilder builder)      //使用擴展方法使我們的中間件對外開放。
        {
            return builder.UseMiddleware<RequestTestMiddleware>();  //將我們中間件加入到IApplicationBuilder中去。
        }
    }
  //在StartUp 中使用我們的自定義中間件。
    app.UseRequestTest();

 

 

Http請求管道的模擬構建

 1     /// <summary>
 2     /// 拿到請求上下文,返回一個委託
 3     /// </summary>
 4     /// <param name="contex"></param>
 5     /// <returns></returns>
 6     public delegate Task RequestDelegate(Context contex);
 7     /// <summary>
 8     /// 模擬http請求上下文
 9     /// </summary>
10     public class Context
11     {
12 
13     }
RequestDelegate和Context
 1         public static IList<Func<RequestDelegate, RequestDelegate>> _list = new
 2             List<Func<RequestDelegate, RequestDelegate>>();
 3         static void Main(string[] args)
 4         {
 5             Use(next =>                                 //加入中間件1
 6             {
 7                 return context =>
 8                 {
 9                     Console.WriteLine("this is use middleware1");
10                     return next.Invoke(context);
11                 };
12             });
13             Use(next =>                               //加入中間件2
14             {
15                 return context =>
16                 {
17                     Console.WriteLine("this is use middleware2");
18                     return next.Invoke(context);
19                 };
20             });
21             RequestDelegate end = context =>
22             {
23                 Console.WriteLine("this is end...");        //管道
24                 return Task.CompletedTask;      
25             };
26             _list.Reverse();
27             foreach (var middleware in _list)
28             {
29                 end = middleware.Invoke(end);
30             }
31             end.Invoke(new Context());              //實例化一個上下文實例
32             Console.ReadLine();
33         }
34         /// <summary>
35         /// 將middleware 加入到list(applicationbuilder)中
36         /// </summary>
37         public static void Use(Func<RequestDelegate, RequestDelegate> iMiddleware)
38         {
39             _list.Add(iMiddleware);
40         }
Use middleware和管道執行

 Jesse博客學習筆記。傳送門=》 http://video.jessetalk.cn/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章