找回密码
 立即注册
首页 业界区 业界 聊聊 ASP.NET Core 中间件和过滤器的区别

聊聊 ASP.NET Core 中间件和过滤器的区别

钨哄魁 4 天前
引言

不知道你有没有在面试中遇到过这样的问题:"中间件和过滤器的区别是什么?",或者在平时开发中思考过:"一个请求进来,ASP.NET Core 到底是怎么一步步处理它的?"
这篇文章就来聊聊,不会涉及太深的源码,主要面向初级开发者,帮你建立一个清晰的认知。
先说中间件

中间件是 ASP.NET Core 处理 HTTP 请求的基本部件,是框架本身的组成部分。
每一个请求进来后,按照 Use 的注册顺序,依次经过每一个中间件,到达终端后,再按照相反的方向依次返回。一系列中间件串联起来,就组成了 ASP.NET Core 的请求管道。这个模型有人叫"洋葱模型",也有人叫"俄罗斯套娃模型",都是一个意思。
  1. 请求 →  中间件A → 中间件B → 中间件C(终端)
  2. 响应 ←  中间件A ← 中间件B ←
复制代码
中间件可以做什么呢?它收到请求后,可以在请求/响应对象上加点佐料(自己的逻辑),然后调用 next() 把请求传递给下一个中间件。如果不调用 next(),请求就在这里短路了,后面的中间件不会执行,这个中间件就成了终端中间件。
下面是一个简单示例,演示如何自定义一个记录请求耗时的中间件:
  1. // 定义中间件类
  2. public class TimingMiddleware
  3. {
  4.     private readonly RequestDelegate _next;
  5.     public TimingMiddleware(RequestDelegate next)
  6.     {
  7.         _next = next;
  8.     }
  9.     public async Task InvokeAsync(HttpContext context)
  10.     {
  11.         var sw = Stopwatch.StartNew();
  12.         // 调用 next(),请求继续往下走
  13.         await _next(context);
  14.         // next() 返回后,响应正在往回走
  15.         sw.Stop();
  16.         Console.WriteLine($"[{context.Request.Path}] 耗时:{sw.ElapsedMilliseconds}ms");
  17.     }
  18. }
  19. // 在 Program.cs 中注册
  20. var app = builder.Build();
  21. app.UseMiddleware<TimingMiddleware>();  // 注册自定义中间件
  22. app.UseRouting();
  23. app.UseAuthorization();
  24. app.MapControllers();
  25. app.Run();
复制代码
如果你不想单独定义一个类,也可以用 app.Use 直接写一个内联中间件:
  1. app.Use(async (context, next) =>
  2. {
  3.     Console.WriteLine($"请求进来了:{context.Request.Path}");
  4.     await next();  // 传递给下一个中间件
  5.     Console.WriteLine($"响应回来了:{context.Response.StatusCode}");
  6. });
复制代码
这里注册的是终端中间件,不接受 next,请求到这里就结束了,不会再往下传:
  1. app.Run(async context =>
  2. {
  3.     await context.Response.WriteAsync("到终点了,不继续往下走");
  4. });
复制代码
再聊过滤器

过滤器是在路由中间件内部起作用的。
请求经过中间件管道,到达路由中间件后,路由中间件确定了要调用哪个 Controller / Action。在真正执行 Action 的前后,过滤器就夹在这里介入。
用一张简单的示意图来表示:
  1. 请求进来
  2.   → 中间件们
  3.     → 路由中间件(确定目标 Action)
  4.       → 过滤器们(Action 执行前后插手)
  5.         → Action 执行
  6.       ← 过滤器们
  7.     ← 路由中间件
  8.   ← 中间件们
  9. 响应返回
复制代码
正因为过滤器处于路由之后,所以它能拿到 MVC 的上下文信息,比如当前是哪个 Action、Action 上有哪些 Attribute、ModelState 是否合法等等。这是普通中间件做不到的,因为中间件执行的时候,路由还没解析呢。
  1. // 定义过滤器类,继承 ActionFilterAttribute
  2. public class ValidateModelAttribute : ActionFilterAttribute
  3. {
  4.     // 在 Action 执行之前触发
  5.     public override void OnActionExecuting(ActionExecutingContext context)
  6.     {
  7.         if (!context.ModelState.IsValid)
  8.         {
  9.             // ModelState 校验不通过,直接短路,返回 400
  10.             var errors = context.ModelState
  11.                 .Where(e => e.Value?.Errors.Count > 0)
  12.                 .ToDictionary(
  13.                     e => e.Key,
  14.                     e => e.Value!.Errors.Select(x => x.ErrorMessage).ToArray()
  15.                 );
  16.             context.Result = new BadRequestObjectResult(new
  17.             {
  18.                 code = 400,
  19.                 message = "参数校验失败",
  20.                 errors
  21.             });
  22.         }
  23.     }
  24.     // 在 Action 执行之后触发
  25.     public override void OnActionExecuted(ActionExecutedContext context)
  26.     {
  27.         // 可以在这里统一处理响应,比如包一层统一的返回格式
  28.     }
  29. }
复制代码
使用方式很简单,直接作为 Attribute 标注在 Controller 或 Action 上:
  1. // 标注在单个 Action 上
  2. [HttpPost]
  3. [ValidateModel]
  4. public IActionResult CreateUser([FromBody] CreateUserRequest request)
  5. {
  6.     // 走到这里说明 ModelState 已经通过校验
  7.     return Ok(new { message = "创建成功" });
  8. }
  9. // 也可以标注在 Controller 上,对所有 Action 生效
  10. [ApiController]
  11. [ValidateModel]
  12. public class UserController : ControllerBase
  13. {
  14.     // ...
  15. }
复制代码
如果想全局生效,在 Program.cs 里注册就行:
  1. builder.Services.AddControllers(options =>
  2. {
  3.     options.Filters.Add<ValidateModelAttribute>();  // 全局注册
  4. });
复制代码
它俩的区别

中间件过滤器作用范围所有 HTTP 请求,包括静态文件仅限 Controller / Action典型使用场景限流、压缩、跨域、日志、认证权限校验、参数校验、统一响应封装、异常处理一句话总结:中间件是 HTTP 管道的基础设施,过滤器是 MVC 系的切面机制,它们不是同一层次的东西。
给你一个小技巧,不确定用哪个的时候,问自己一个问题:我需要知道当前是哪个 Action 吗? 需要的话用过滤器,不需要的话中间件就够了。
内置清单

最后整理一份 ASP.NET Core 已经提供的常用中间件和过滤器,遇到需求的时候先查查有没有现成的,别重复造轮子。
常用内置中间件:
中间件说明UseRouting路由解析UseAuthentication认证UseAuthorization授权UseStaticFiles静态文件服务UseCors跨域UseExceptionHandler全局异常处理UseHttpsRedirectionHTTPS 重定向UseResponseCompression响应压缩UseRateLimiter限流(.NET 7 新增)内置过滤器:
过滤器说明[Authorize]授权校验[AllowAnonymous]允许匿名访问[RequireHttps]强制 HTTPS[ValidateAntiForgeryToken]防止 CSRF 攻击[ResponseCache]响应缓存[Produces]指定响应内容类型[Consumes]指定请求内容类型
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册