ASP.NET Core - 请求管道与中间件
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 - .NET 6 的入口文件
ASP.NET Core - 请求管道与中间件的更多相关文章
- asp.net core mvc 管道之中间件
asp.net core mvc 管道之中间件 http请求处理管道通过注册中间件来实现各种功能,松耦合并且很灵活 此文简单介绍asp.net core mvc中间件的注册以及运行过程 通过理解中间件 ...
- 配置 ASP.NET Core 请求(Request)处理管道
配置 ASP.NET Core 请求(Request)处理管道 在本节中,我们将讨论使用中间件组件为 asp.net core 应用程序配置请求处理管道. 作为应用程序启动的一部分,我们要在Confi ...
- ASP.NET Core HTTP 管道中的那些事儿
前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Core 中间件系列的,但是中间遇到了很多事情.首先是 NPOI ...
- Asp.Net Core入门之自定义中间件
什么是中间件? 这里引用官方解释: 中间件是用于组成应用程序管道来处理请求和响应的组件.管道内的每一个组件都可以选择是否将请求交给下一个组件.并在管道中调用下一个组件之前和之后执行某些操作.请求委托被 ...
- 在ASP.NET Core 中使用Cookie中间件
在ASP.NET Core 中使用Cookie中间件 ASP.NET Core 提供了Cookie中间件来序列化用户主题到一个加密的Cookie中并且在后来的请求中校验这个Cookie,再现用户并且分 ...
- 用.Net Core控制台模拟一个ASP.Net Core的管道模型
在我的上几篇文章中降到了asp.net core的管道模型,为了更清楚地理解asp.net core的管道,再网上学习了.Net Core控制台应用程序对其的模拟,以加深映像,同时,供大家学习参考. ...
- 在ASP.NET Core 中使用Cookie中间件 (.net core 1.x适用)
在ASP.NET Core 中使用Cookie中间件 ASP.NET Core 提供了Cookie中间件来序列化用户主题到一个加密的Cookie中并且在后来的请求中校验这个Cookie,再现用户并且分 ...
- asp.net core 3.1 自定义中间件实现jwt token认证
asp.net core 3.1 自定义中间件实现jwt token认证 话不多讲,也不知道咋讲!直接上代码 认证信息承载对象[user] /// <summary> /// 认证用户信息 ...
- Asp.Net HttpApplication请求管道与Session(二)
Asp.Net 回话的创建与结束 LogHelper.LogHelper _log = new LogHelper.LogHelper(); /// <summary> /// 程序开始- ...
- Asp.Net HttpApplication请求管道与Session(一)
1.请求处理顺序执行事件 /********************请求处理顺序执行事件**********************/ /// <summary> /// 请求入站 /// ...
随机推荐
- RabbitMq简单模式
RabbitMq简单模式 定义一个生产者,负责发送消息到队列中 /** * @author zjh * 生产者发信息 */ public class Producer { /** * 队列名称 */ ...
- 【红队技巧】Windows存储的密码获取
[红队技巧]Windows存储的密码获取 免责声明: 使用前提 支持版本 利用方式 参考: 免责声明: 本文章仅供学习和研究使用,严禁使用该文章内容对互联网其他应用进行非法操作,若将其用于非法目的,所 ...
- docker使用bind9实现域名解析
目录 刷新服务 修改配置文件 从 114 缓存 查询 数据 可以 dig 无法 ping 查看 已经 区域 解析,并添加 新的 解析 项 在 linux 安装 局域网 cert rndc 查看 默认的 ...
- php变量规范命名用了记得消除,保证唯一性
PHP中的命名规则 类的命名 在为类(class )命名前首先要知道它是什么.如果通过类名的提供的线索,还是想不起这个类是什么的话,那么就说明设计存在问题. 超过三个词组成的混合名是容易造成系统各个 ...
- WSL优化之SSH远程登录篇
Some of the most devastating things that happen to you will teach you the most. 有些最打击你的事情反而教会你的东西越多. ...
- MIUI12解决安装charles抓包安装证书后还是提示证书不安全
前言 我抓包这么长时间,这个问题我还是第一次遇到,导致我反复试验,明明安装证书还是提示不安全.我用新买的手机MIUI 12系统弄了半天 解决方案 首先下载证书这部分是一个坑,小米 MIUI 12系统下 ...
- uniCloud云开发入门以及对传统开发方式的思考
事情缘由 作为选修了移动互联网应用的一员,老师讲的什么JS基础,还有ES6和uniapp,当然是没怎么听,因为是之前大二的时候都大概看过. 但是快到期末,老师讲了云开发,并且布置了与此相关的大作业,自 ...
- 深入理解 MySQL 的事务隔离级别和 MVCC 机制
前言 我们都知道 MySQL 实现了 SQL 标准中的四个隔离级别,但是具体是如何实现的可能还一知半解,本篇博客将会从代码层面讲解隔离级别的实现方式,下面进入正题. 事务 考虑这样一个场景:博主向硝子 ...
- PhaApi NOTORM 实现分表分库
通过自增ID取模要分表的数量,便可得到表名.例如log表分成100张表:log_1,log2...,log100. 每次数据库CURD都先通过获取ID分配到相对应的表,例如:id=66,取模后的结果是 ...
- Jmeter 之吞吐量控制器
作用: 吞吐量控制器可用来模拟混合场景的压测业务,即一部分用户执行场景A,一部分用户执行场景B 字段说明: Total Excutions:执行请求总数 Percent Excutions:执行线程数 ...