WebAPI-中间件

WebAPI-中间件

ASP.NETCore中,filter的概念更像是一个面向AOP编程的增强类

而ASP.NETCore中间件的概念,更像是JavaWeb的Filter或者是SpringMVC中的拦截器一样

需要注意的是,Java中也有中间件的概念,不过更多指的是Tomcat或Redis这一类的应用服务

大部分时间,我们极少需要自己定义中间件,一般都使用框架定义好的中间件,所以对框架提供的中间件要熟悉,另外要熟悉HttpContext对象的常用成员


Map管道

在启动类中,我们可以见到很多app.Use方法来定义的中间件

在这里,我们可以使用Map来自定义管道,实现不同的http请求路径而使用不同的中间件

定义在Map管道之外的中间件,则应用于所有请求

除了Map方法之外,还有MapGet、MapPost、MapWhen等指定管道的方法,但实际项目中,如果不是开发框架,比较少用到Map

中间件的注册顺序很重要

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        var app = builder.Build();

        // 指定处理“/test”路径请求的管道 
        app.Map("/test", async testBuilder =>
        {
            // 第一个中间件
            testBuilder.Use(async (context, next) =>
            {
                context.Response.ContentType = "text/html";
                await context.Response.WriteAsync("1 Start<br/>");
                await next.Invoke();
                await context.Response.WriteAsync("1 End<br/>");
            });
            // 第二个中间件
            testBuilder.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("2 Start<br/>");
                await next.Invoke();
                await context.Response.WriteAsync("2 End<br/>");
            });
            //Run终点
            testBuilder.Run(async ctx => { await ctx.Response.WriteAsync("hello,it is run<br/>"); });
        });

        app.Run();
    }
}

Context

每一次HTTP请求,框架会自动生成一个HttpContext类型的对象,称之为上下文,可以记录了请求路径、请求参数、请求客户端、响应报文、响应流、用户、自定义Items等信息。在中间件的前后逻辑和控制器中,均可以对HttpContext对象进行读写操作


Next

在一个中间件中,有三部分组织,①前逻辑;②next方法;③后逻辑

HTTP请求到达服务器后,先由框架进行请求解析,然后进入第一个中间件,先执行前逻辑,然后由中间件自己决定是否执行next.Invoke(),如不执行,则请求中断,如执行,则请求进入下一个中间件

当Controller控制器方法执行之后,再逆向执行中间件进行响应处理


中间件类

同样的,我们可以自定义中间件类,将中间件代码放入其中

中间件类是一个很普通的类,他不需要继承任何父类方法或实现任何接口,但这个类需要有一个构造方法,构造方法至少有一个RequestDelegate类型的参数

这个类型的参数对象(next)用来放行中间件,让其到达下一个中间件

这个类需要定义一个名字为Invoke或InvokeAsync的方法,方法至少有一个HttpContext类型的参数(context),其方法的返回值必须是Task类型

注:无论是中间件类还是Invoke方法,都可以通过DI来注入其他对象

using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;

public class LoggingMiddleware
{
    private readonly RequestDelegate _next;

    public LoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 请求前的日志记录
        Console.WriteLine($"Request started: {context.Request.Method} {context.Request.Path}");

        // 调用下一个中间件
        await _next(context);

        // 响应后的日志记录
        Console.WriteLine($"Request completed with status code: {context.Response.StatusCode}");
    }
}

注册中间件

需要注意的是,通过UseMiddleware<>方法注册自定义中间件,而不是Use方法

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);	
        var app = builder.Build();
       
        // 通过UseMiddleware方法注册自定义中间件
        app.UseMiddleware<TestMiddleware>();

        app.Run();
    }
}

深度理解

ASP.NETCore框架内置很多中间件,通过这些内置的中间件,我们可以快速的构建一个WebAPI甚至是MVC的架构

对于Filter(筛选器)而言,他们有一些相同点和不同点:

  • 中间件可以处理所有的请求,而Filter只能处理对控制器的请求
  • 中间件运行在一个更底层、更抽象的级别
  • 中间件和Filter可以完成很多相似的功能,例如:
    • 未处理异常中间件和未处理异常Filter
    • 请求限流中间件和请求限流Filter
  • 优先选择使用中间件