当前位置:网站首页>浅聊一下中间件

浅聊一下中间件

2022-07-04 22:23:00 InfoQ

先浅聊一下基本概念

其实关于中间件,它也不是什么神秘的东西。咱们既然定位在了浅聊(主要是深了咱也不会),就单独拿出几个典型的应用场景来聊一下。注意咱这都是小场面,可不是那个广义的中间件,只是在dotnetcore系统框架里的中间件。
我感觉中间件,就是把整个网络请求过程中的那些系统不应该管,或者管理起来很麻烦的部分,单独拎出去,交给中间件去做统一的处理。
打个比方就是,我们上班,是为了工作挣钱滴,但是找到工作以后,发现还要处理什么档案啊,社保啊,公积金啊等等乱七八糟的事儿,既麻烦,又不可或缺。而在实际生活中都会有一些专门的“行政办事大厅”来处理这些事儿,
我们开发的系统也是一样,应该是以业务为中心,为实际的业务需求服务的。而如果系统中有过多的代码用来处理与业务不想干的东西,就会大幅提高系统代码的复杂度,造成后续业务的扩展非常麻烦。上面提到的那些“与业务不相干”的东西,大体包含了以下几个方面:日志,授权,验签,流量控制等等。
没错,中间件就是为了解决这些事情而出现的。

再浅看一个实际案例

在DotnetCore项目里,定义中间件非常方便,还是以之前那篇《》里的项目为案例,现在来定义一个中间件,来看一下运行效果(这里的案例我有参考桂素伟老师写的一些案例,推荐大家看一下桂老师的文章)。
首先,创建一个类文件,随便写几行代码,注意其中的
RequestDelegate
是一种委托类型,微软官方文档中也给出了解释,这个类,就是专门为处理http请求而诞生的,没有它,框架也就失去了对HTTP请求的处理能力。
public class TestMiddleware1
{
 private readonly RequestDelegate _next;
 public TestMiddleware1(RequestDelegate next)
 {
 _next = next;
 }

 public async Task InvokeAsync(HttpContext context)
 {
 AnsiConsole.MarkupLine($"[red]我是第1个中间件,我过来了-{DateTime.Now}[/]");
 await _next(context);
 AnsiConsole.MarkupLine($"[red]我是第1个中间件,我退下了-{DateTime.Now}[/]");
 }
}
之后,我们在定义一个静态的扩展类来调用管道的处理方法
public static class TestMiddlewareExtensions
{
 public static void UseTest(this WebApplication app)
 {
 app.UseMiddleware<TestMiddleware1>();
 }
}
最后,就可以在主函数(Program.cs或者StartUp.cs)中调用中间件了

var app = builder.Build();
...其他中间件
app.UseTest();
看下运行效果。
null
到这里,中间件就已经开始工作了。
定义中间件,还可以直接通过表达式的形式来定义,直接在主函数中编写即可,不过这样可能会造成代码不够清晰,但在一些特殊情况这样做还是有一定必要的。
代码如下
var app = builder.Build();

app.UseTest();
app.Use(async (context, next) =>
{
 AnsiConsole.MarkupLine($&quot;[Yellow]我是第2个中间件,我来自入口文件,我过来了-{DateTime.Now}[/]&quot;);
 await next(context);
 AnsiConsole.MarkupLine($&quot;[Yellow]我是第2个中间件,我来自入口文件,我退下了-{DateTime.Now}[/]&quot;);
});
运行效果如下
null
可以看到,中间件的执行顺序是有区别的,先注册的中间件,最后返回Response,这一点在实际使用的时
候要注意,顺序不要搞错了,尤其是那些需要做一些特殊的业务处理的中间件。关于这一点,可以参见
微软的官方文档

null
然后,还是回到第一种定义中间件的方式。当我们需要定义多个中间件函数时,还是应该尽可能的把中间件单拎到独立的文件中,这样代码会更加清晰。第一个例子,如果注册多个中间件,就可以这样做
public class TestMiddleware1
{
 private readonly RequestDelegate _next;
 public TestMiddleware1(RequestDelegate next)
 {
 _next = next;
 }

 public async Task InvokeAsync(HttpContext context)
 {
 AnsiConsole.MarkupLine($&quot;[red]我是第1个中间件,我过来了-{DateTime.Now}[/]&quot;);
 await _next(context);
 AnsiConsole.MarkupLine($&quot;[red]我是第1个中间件,我退下了-{DateTime.Now}[/]&quot;);
 }
}

public class TestMiddleware2
{
 private readonly RequestDelegate _next;
 public TestMiddleware2(RequestDelegate next)
 {
 _next = next;
 }

 public async Task InvokeAsync(HttpContext context)
 {
 AnsiConsole.MarkupLine($&quot;[green]我是第2个中间件,我过来了-{DateTime.Now}[/]&quot;);
 await _next(context);
 AnsiConsole.MarkupLine($&quot;[green]我是第2个中间件,我退下了-{DateTime.Now}[/]&quot;);
 }
}

public class TestMiddleware3
{
 private readonly RequestDelegate _next;
 public TestMiddleware3(RequestDelegate next)
 {
 _next = next;
 }

 public async Task InvokeAsync(HttpContext context)
 {
 AnsiConsole.MarkupLine($&quot;[blue]我是第3个中间件,我过来了-{DateTime.Now}[/]&quot;);
 await _next(context);
 AnsiConsole.MarkupLine($&quot;[blue]我是第3个中间件,我退下了-{DateTime.Now}[/]&quot;);
 }
}


public static class TestMiddlewareExtensions
{
 public static void UseTest(this WebApplication app)
 {
 app.UseMiddleware<TestMiddleware1>();
 app.UseMiddleware<TestMiddleware2>();
 app.UseMiddleware<TestMiddleware3>();
 }
}
运行之后,呈现的效果就是这样
null
好了,大概就是这样,聊的比较浅,中间件具体实例也只是简单打印了一点文字,实际是要写日志,还是做监控还是干什么的,就根据实际的业务需求去调整就好了。
晚安啦~
原网站

版权声明
本文为[InfoQ]所创,转载请带上原文链接,感谢
https://xie.infoq.cn/article/e784da4587baf62230f783965