一、Core 處理HTTP請求流程app
二、中間件(Middleware)&&處理流程async
三、建立自定義中間件&&模擬Core的請求管道ide
Http請求來到以後,會先由WebServer( 例如IIS,Nginx) 拿到而後丟給Kestrel WebServer,再有Kestrel 將Http請求封裝爲HttpContext後傳入給.net core 請求管道(RequestDelegate)。HttpContext通過一系列middleware後返回response給WebServer。學習
微軟官方文檔給出的解釋是這樣的:中間件是加載在應用程序管道中以處理和相應請求的組件。其中每一個組件均可以 選擇是否能夠將請求傳遞給管道中下一個組件;能夠在調用管道的下一個組件以前或以後執行。下面是官方文檔給出的一張圖。ui
也就是說一個http請求的處理過程爲,通過中間件1的處理邏輯(這個時候能夠在中間件1中對httpcontext作一些處理,例如寫入一段內容),調用next()方法,進入到中間件2中,重複以上步驟。最終,全部中間件的處理邏輯的輸出結果都會疊加到HttpResponse中去。this
.net core 中有三種方式調用中間件。在StartUp的Configure方法中,分別能夠調用app.Use(),app.Run(),app.Map() 來調用中間件。接下來讓咱們來看下:spa
app.Use方法有兩個重載形式:.net
第一個方法接收一箇中間件,第二個方法接收一個上下文和一箇中間件。讓咱們來分別調用下:3d
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 ,以下圖code
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 自帶的中間件
管道的實現機制由ApplicationBuilder 和 RequestDelegate 組成。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 }
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 }
Jesse博客學習筆記。傳送門=》 http://video.jessetalk.cn/