一次http请求的过程,就是对一个Request请求进行若干次逻辑处理,并最终设置Response的过程。从代码的实现维度看,因为Request和Response都在HttpContext里,可将此过程表示为“以一个httpContext为输入的委托函数”,即delegate Task RequestDelegate(HttpContext context),为方便此文的描述,咱们将此委托函数暂时称为“请求处理逻辑”缓存
而中间件的做用,就是在请求的后面加入一个处理逻辑,这个处理逻辑是以“前一个请求处理逻辑”为输入,并通过中间件本身的处理后,返回一个“新的请求处理逻辑”。因此从代码上可将“中间件”表式为以一个“请求处理逻辑”为输入并返回另外一个“请求处理逻辑”的委托,即Func<RequestDelegate,RequestDelegate>。而多个中间件即表示为List<Func<RequestDelegate,RequestDelegate>>。app
Asp.net core中间件的核心功能就是如何将一系列的中间件,合并成一个“请求处理逻辑”的过程,即如何将List<Func<RequestDelegate,RequestDelegate>>合并生成一个RequestDelegate。合并逻辑以下asp.net
上面的代码有两个地方要注意函数
一、asp.net core会默认在请求的最后加入一个“404”处理的中间件。 ui
二、合并时,组件是先反序后再循环的this
因先加入的中间件要先执行,因此在合并时,第一个中间件要最后合并,即要倒序后再循环合并中间件spa
使用中间件有四种方法:Use、Run、Map和使用Middleware class,但前三种方法最终调用的都是Use方法,咱们来看看Use方法的实现逻辑,以下 .net
即use方法只是在中间件列表(_components)的最后再加入一个中间件设计
下面详细描述四种方法的用法3d
Ues的用法有两种
用法一
调用IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware),此用法需在middleware委托里本身控制是否要进入下一个中间件,而且要本身建立一个RequestDelegate并返回,写法会比较复杂。
示例以下
用法二
调用IApplicationBuilder Use(this IApplicationBuilder app, Func<HttpContext, Func<Task>, Task> middleware),这是一个扩展方法,此方法不用本身建立RequestDelegate并返回,写法比较简洁。它最终调用的方法仍是用法一中的实现,此方法的实现代码以下。
示例以下
需注意:上面的两种Use用法,在第二个中间件时,并无再调用下一个中间件,这是为了确保http请求不会进入到asp.net core默认的最后一个404中间件,由于最后一个404中间件设置了status code,而一但response body以前已经开始写入时,是不能再改变status code或是request header的,不然会报错。微软的官方文档里要求中间件的使用要遵循以下规则:如response body改变后就不要再调用下一个中间件,避免下一个中间件对上一个中间件的httpcontext内容的污染。(本文示例为演示目的,未遵循此约定)
run方法的实现代码以下
注意:从run方法的实现的代码能够看出,run是不会再执行下一个中间件的,因此第一个中间run方法后面的中间件都不会起做用。因此通常用run时都是放在中间件的最后
map其实准确来讲不是中间件的用法,而是新开一个“中间件请求路线分支”,在这个“分支”里,能够再用use和run方法来组件一个新的中间件逻辑。
示例以下
如上示例,请求地址当能匹配上/test里,才会启用map里的中间件
Middleware class不须要继承任何类或是接口,但必须有名为Invoke,返回类型为Task,且第一个参数为HttpContext类型的方法。
示例以下
中间件名称 |
如何使用及说明 |
Authentication |
App.UseAuthentication,验证当前请求的用户,并设置HttpContext.User,当OAuth callbacks时,会停止执行下一个中间件。放到要用到用户验证的中间件前面 |
Static File |
app.UseStaticFiles(),判断当前请求是否为静态文件,若是是则停止执行下一个中间件,不然继续下一个中间件。放到管道的最前 |
Response Caching |
app.UseResponseCaching(),缓存中间件 |
MVC |
app.UseMvc(),将MVC引入到中间件管道,若是请求的地址能找到对应的MVC路由,则停止执行下一个中间件。放到管道的最后。 |
Exception |
app.UseDeveloperExceptionPage();或app.UseExceptionHandler();用于处理程序的异常信息。放到管道的最前 |
Authorization |
受权中间件。不需直接引用,App.UseMvc()会在内部调用,并配合app.UseAuthentication()一块儿使用。 |
一、经过use,run,map,middleware class四种方法使用
二、使用多个中间件时,需注意中间件的顺序
3、在设计中间件时,请遵循“责任分离”原则,即一个中间件只对“单一责任”进行处理,如验证用户、受权等。
4、若是对response body作了修改后,请不要再执行下一个中间件