1. 请求管道

请求管道是什么?请求管道描述的是一个请求进到我们的后端应用,后端应用如何处理的过程,从接收到请求,之后请求怎么流转,经过哪些处理,最后怎么返回响应。请求管道就是一次请求在后端应用的生命周期。了解请求管道,有助于我们明白后端应用是怎么工作的,我们的代码是怎么工作的,在我们的业务代码执行前后经过哪些步骤,有助于我们之后更好的实现一些AOP操作。

请求管道是 .net 应用的一个最基本的概念。在 .net core 中,微软对框架底层进行了全新的设计,相对于原本的ASP.NET中的全家桶模式的管道模型,.net core的管道模型更加灵活便捷,可做到热插拔,通过管道可以随意注册自己想要的服务或者第三方服务插件,这也是.net core性能更好的原因。

以上是微软官方文档中的管道模型图。从图中可以看到 服务器接收到请求之后,将接收到的请求向后传递,依次经过一个个 Middleware 进行处理,然后由最后一个 MiddleWare 生成响应内容并回传,再反向依次经过每一个 Middleware,直到由服务器发送出去。整个过程就像一条流水线一样,管道这个词是很形象的,而 Middleware 就像一层一层的“滤网”,过滤所有的请求和响应。

2. 中间件

管道之中,对请求、响应进行加工处理的模块是 Middleware,也就是中间件。中间件本质上是一个委托。

2.1 工作模式

从上面的图可以看出,每一个中间件都会被执行两次,在下一个中间件执行之前和之后各执行一次,分别是在处理请求和处理响应,只有一个中间件是例外的,那就是最后一个中间件,它后面没有下一个中间件,所以执行到它管道就会回转。

这代表了中间件的两种工作模式,也是中间件的两种基本注册方式。中间件本质上是一个委托,在代码实现上就体现在委托的入参有所不同以及注册调用的方法不同。

中间件两种最基本的注册方式:

  • Use 方法注册

    • use 注册的中间件会传入next参数,在处理完本身的逻辑之后可以调用 next() 去执行下一个中间件
    • 如果不执行,就等于Run
  • Run 方法注册
    • Run 只是执行,没有去调用Next ,一般作为终结点。
    • Run 方法注册,只是一个扩展方法,最终还是调用Use方法

在代码中分别是以下方式:

app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello Middlerware !");
if(context.Request.Query.TryGetValue("query", out var query))
{
await context.Response.WriteAsync(query);
}
await next();
await context.Response.WriteAsync("End Middleware !");
}); app.Run(async context =>
{
await context.Response.WriteAsync("Hello last Middleware");
});

最后的执行结果如下,也可以从代码执行的先后顺序看出管道流动的顺序。当前中间件手动调用 next() 之后,就进入下一个中间件,下一个中间件处理完成之后,按照管道的顺序再一个一个回传。在这个过程中一直不变,被管道传递的就是HttpContext,而我们拿到 HttpContext,即可以通过 Request 和 Response 对当前这一次的请求做任何处理了。

通过分析asp.net core的源码,可以看到在我们调用 Run() 的时候,实际上还是调用了 Use() 方法。

而 Use() 方法中,主要的逻辑仅仅只是将相应的委托存放到集合中

之后在 build 方法调用的时候才一个一个地调用中间件委托。

除了上面的 Use() 、Run() 两个最基本的方法注册中间件之外,还有另外一些方法,如通过 Map() 方法注册中间件,这种方式会创建一个新的管道分支,在路由满足Map的规则时,请求则转型新的管道分支,最后沿着管道分支返回响应,而不走原有的管道。

app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello Middlerware1 ! ");
if(context.Request.Query.TryGetValue("query", out var query))
{
await context.Response.WriteAsync(query);
}
await next();
await context.Response.WriteAsync("End Middleware1 ! ");
}); app.Map("/map", app =>
{
// map方法中的委托,传入的时IApplicationBuilder, 在这里相当于一个新的管道,也可以和主管道一样进行任意操作
app.Run(async context =>
{
await context.Response.WriteAsync("Hello map Middleware pipeline ! ");
});
}); app.Run(async context =>
{
await context.Response.WriteAsync("Hello last Middleware ! ");
});

执行结果如下:

其他的分支管道创建方式,如 MapWhen,和 Map 大同小异,只是对于匹配判断的方式有所不同。像微软内置中间件中的静态文件中间件,MVC 中间件,其实都是以分支管道的方式实现的,一旦匹配到请求就会走管道分支。

2.2 中间件的使用配置

使用一个中间件需要在 .net core 的入口文件中进行配置,如果是 .net 6版本,那只要在 program.cs 文件中进行配置即可,通过 WebApplication 对象,也就是 app 调用相关的方法。

如果是 .net 6 以下版本,可以在 startup.cs 文件中的 Configure 方法中配置。.net 6 与之前版本入口文件的不同上一篇文章也讲过,这里就不赘述了。

这里可以看得到,一些中间件的调用并没有直接使用 Use() 和 Run(),毕竟将各个中间件的处理逻辑全部放在入口文件很不好管理,而且也很不优雅。这里涉及到了中间件封装的约定规则,一般情况下封装一个中间件都会提供一个 Use[Middleware] 方法以供使用者进行中间件的调用,WebApplication 对象的 UseXXX 方法都是中间件调用的方法。

2.3 ASP.NET Core 框架内置中间件

ASP.NET Core 框架之中内置有很多中间件,并且我们通过 VS 创建某一个类型的项目时,如MVC、Razor Page,初始化的项目代码中会帮我们配置好一些中间件。

以上为官方文档中列出的内置中间件,可以看到在列表中对每个中间件的顺序进行了说明。

管道中的中间件排列是有先后之分的,请求和响应按照中间件的排列顺序进行传递,这也是我们代码逻辑执行的顺序,而且一些中间件需要依赖于其他中间件的处理结果,或者必须在某些中间件前先执行,否则就会出问题了。

而中间件插入到管道中的顺序,就是依据我们在入口文件中调用相应中间注册方法的顺序,所以代码的前后顺序非常重要,一旦写错了就会出现很多意想不到的的Bug。

向 Program.cs 文件中添加中间件组件的顺序定义了针对请求调用这些组件的顺序,以及响应的相反顺序。 此顺序对于安全性、性能和功能至关重要。这是官方文档中的原话。

官方文档给出了典型MVC应用的管道中间件顺序,这里其实不止MVC,Razor Page、Web Api 也是这样的管道模型,如下图。这里也明确了我们自定义的中间件应该插入到哪个位置。

更多的内置中间件的作用,以及相应的管道顺序要求,请详细阅读一下官方文档,这里就不细说了。

参考文章:

ASP.NET Core 中间件

ASP.NET Core 系列:

目录:ASP.NET Core 系列总结

上一篇: ASP.NET Core - .NET 6 的入口文件

ASP.NET Core - 请求管道与中间件的更多相关文章

  1. asp.net core mvc 管道之中间件

    asp.net core mvc 管道之中间件 http请求处理管道通过注册中间件来实现各种功能,松耦合并且很灵活 此文简单介绍asp.net core mvc中间件的注册以及运行过程 通过理解中间件 ...

  2. 配置 ASP.NET Core 请求(Request)处理管道

    配置 ASP.NET Core 请求(Request)处理管道 在本节中,我们将讨论使用中间件组件为 asp.net core 应用程序配置请求处理管道. 作为应用程序启动的一部分,我们要在Confi ...

  3. ASP.NET Core HTTP 管道中的那些事儿

    前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Core 中间件系列的,但是中间遇到了很多事情.首先是 NPOI ...

  4. Asp.Net Core入门之自定义中间件

    什么是中间件? 这里引用官方解释: 中间件是用于组成应用程序管道来处理请求和响应的组件.管道内的每一个组件都可以选择是否将请求交给下一个组件.并在管道中调用下一个组件之前和之后执行某些操作.请求委托被 ...

  5. 在ASP.NET Core 中使用Cookie中间件

    在ASP.NET Core 中使用Cookie中间件 ASP.NET Core 提供了Cookie中间件来序列化用户主题到一个加密的Cookie中并且在后来的请求中校验这个Cookie,再现用户并且分 ...

  6. 用.Net Core控制台模拟一个ASP.Net Core的管道模型

    在我的上几篇文章中降到了asp.net core的管道模型,为了更清楚地理解asp.net core的管道,再网上学习了.Net Core控制台应用程序对其的模拟,以加深映像,同时,供大家学习参考. ...

  7. 在ASP.NET Core 中使用Cookie中间件 (.net core 1.x适用)

    在ASP.NET Core 中使用Cookie中间件 ASP.NET Core 提供了Cookie中间件来序列化用户主题到一个加密的Cookie中并且在后来的请求中校验这个Cookie,再现用户并且分 ...

  8. asp.net core 3.1 自定义中间件实现jwt token认证

    asp.net core 3.1 自定义中间件实现jwt token认证 话不多讲,也不知道咋讲!直接上代码 认证信息承载对象[user] /// <summary> /// 认证用户信息 ...

  9. Asp.Net HttpApplication请求管道与Session(二)

    Asp.Net 回话的创建与结束 LogHelper.LogHelper _log = new LogHelper.LogHelper(); /// <summary> /// 程序开始- ...

  10. Asp.Net HttpApplication请求管道与Session(一)

    1.请求处理顺序执行事件 /********************请求处理顺序执行事件**********************/ /// <summary> /// 请求入站 /// ...

随机推荐

  1. Rust构建环境搭建

    ###安装涉及的概念rustup : 安装rust和管理版本的工具,当前rust尚处于发展阶段,存在三种类型的版本,稳定版.测试版.每日构建版本,使用rustup可以在这三种的版本之间切换,默认是稳定 ...

  2. IPV4地址详解

    在互联网时代,相信会上网的人应该对IP地址都不是很陌生.就像我们每个人都有一个身份证号码一样,网络里的每个终端都使用一个IP地址用于标示自己.那么你知道哪些是保留地址?哪些是特殊地址吗? 一.保留地址 ...

  3. 我的第一个项目(二):使用Vue做一个登录注册界面

    好家伙,   顶不住了,太多的bug, 本来是想把背景用canvas做成动态的,但是,出现了各种问题 为了不耽误进度,我们先把一个简单的登录注册界面做出来 来看看效果:  (看上去还不错) 本界面使用 ...

  4. Windows之应用安装程序 —— winget

    大家都用过Linux中的应用程序安装工具,如yum.apt.rpm等工具进行安装自己想要的一些工具或则软件之类的,当然Linux操作系统还是很强大的有很多类似的命令来安装我们所需要的程序,但是wind ...

  5. sqlserver数据库还原

    这里是从A服务器备份的数据库文件,还原到本地B电脑的数据库.因数据库版本相同,故而未曾出现其他版本问题 1.有个bak的备份文件 2.在B电脑新建一个数据库test. 3.设置test数据库的访问限制 ...

  6. 把Mybatis Generator生成的代码加上想要的注释

    作者:王建乐 1 前言 在日常开发工作中,我们经常用Mybatis Generator根据表结构生成对应的实体类和Mapper文件.但是Mybatis Generator默认生成的代码中,注释并不是我 ...

  7. devexpress 中advBandedGridView内容自动换行和调整自适应行高

    首先是自动换行,可以创建一个repositoryItemMemoEdit 并绑定到需要换行的列中 再设置一下repositoryItemMemoEdit高度自适应,这样子就完成了自动换行了 repos ...

  8. C温故补缺(十三):可变参数

    可变参数 stdarg.h 头文件提供了实现可变参数功能的函数和宏.具体步骤如下: 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数,一般传入参数的个数. int func(int n ...

  9. 一次MTU问题导致的RDS访问故障

    导语 VPN是一种通过公网连接两个或多个私网站点的专用网络,使得这些站点仿佛是通过专线连接在一起.IPSec是一套协议框架,用于保证数据传输的私密性,完整性,真实性.但是VPN网络经常会带来一些连通性 ...

  10. 《吐血整理》高级系列教程-吃透Fiddler抓包教程(35)-Fiddler如何抓取微信小程序的包-下篇

    1.简介 通过前边和宏哥的学习,我们了解到Android 7.0 之后增加了对第三方证书的限制,抓包工具(charles.fiddler等)提供的证书都无法通过校验,也就无法抓取HTTPS请求了,对测 ...