在上一篇文章中,我们完成了 .NET Web 框架的基本组成和结构,在这一篇中我们重点来描述使用中间件、过滤器以及属性来构建HTTP 管道,并处理各类请求。
[NET后端框架1-Web后端框架的组成](https://blog.youkuaiyun.com/weixin_55693845/article/details/146315855?
基本概念
ASP.NET Core应用的HTTP的管道搭建
服务器(Server):作为管道入口,负责请求监听与响应输出(如Kestrel服务器默认监听5000端口)
中间件链(Middleware Chain):由多个中间件按注册顺序组成处理链,每个中间件通过Func<RequestDelegate, RequestDelegate>委托实现逻辑叠加
框架集成层:通过Startup.Configure方法配置中间件,并衔接MVC/Web API等上层框架。
中间件:ASP.NET Core请求处理管道的全局组件、核心组件,通过Startup.Configure
注册的无状态处理单元,贯穿整个HTTP请求生命周期(如身份验证、请求日志)。它独立于 MVC 框架,直接处理从客户端发来的请求,并能决定是否将请求传递给下一个中间件,最终生成响应返回客户端
筛选器:MVC框架内的AOP实现机制,在路由匹配后发挥作用。以控制器/方法为作用域,用于对特定的控制器或方法执行前后进行干预,实现如参数验证、授权检查等功能。
属性:属性是一种元数据标记(Metadata),标记于方法、控制器。以声明的方式将筛选器绑定到特定代码单元(如[Authorize]
标记控制器访问权限),是筛选器的主要实现手段之一。属性本身不是处理逻辑,需要与筛选器机制配合使用。
一、中间件、筛选器、属性
属性通过特性标记(如[Route]
)与控制器/方法形成绑定关系,实现筛选器的局部作用域控制
二、请求处理流程
三、作用域区分
(一)中间件作用域
中间件作用域HTTP管道(跨MVC),使用代码配置。
作用域特征:
1. 全流程覆盖:从请求接收到响应返回全程参与
2. 依赖执行顺序:注册顺序决定处理层级(比如异常中间件需先注册)
3. 管道短路能力:可中断请求传递直接响应(比如JWT验证失败返回401等)
(二)筛选器作用域
筛选器作用于MVC框架内,可以注册或者特性的方式绑定。
作用域控制策略:
1. 全局注册:通过services.AddMvc(options => options.Filters.Add())
影响所有控制器
2. 控制器级:通过类特性标记(如[TypeFilter(typeof(CustomFilter))]
)
3. 方法级:通过Action特性标记(如[ServiceFilter(typeof(LogFilter))]
)
四、代码实战:定义、注册与使用
(一)中间件
-
定义 :创建一个继承自
IMiddleware
接口的类,在其中实现InvokeAsync
方法,编写中间件的处理逻辑。例如,以下是一个 Token 校验中间件的定义:-
/// <summary> /// Token校验中间件 /// </summary> public class TokenMiddleWare : IMiddleware { /// <summary> /// token服务 /// </summary> TokenService _tokenService; /// <summary> /// 构造函数,注入tokenservice /// </summary> /// <param name="tokenService"></param> public TokenMiddleWare(TokenService tokenService) { _tokenService = tokenService; } /// <summary> /// 中间件调用 /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public async Task InvokeAsync(HttpContext context, RequestDelegate next) { try { //前逻辑处理 // 获取当前请求的Endpoint var endpoint = context.GetEndpoint(); var skiptoken= endpoint?.Metadata.OfType<SkipTokenAttribute>().Any(); if (skiptoken == true) //未标记禁用token检查 { if (!_tokenService.CheckToken(context)) //校验token有效性,token从header中解析获取 { _ = Res401Async(context); //校验失败,返回401错误 return; } } //进入下一个中间件 await next(context); //后逻辑处理 } catch (Exception ex) { _ = Res500Async(context); //处理异常,返回服务器500错误 } } /// <summary> /// 登录后返回401 /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task Res401Async(HttpContext context) { context.Response.StatusCode = 401; // context.Response?.Headers?.Add("Content-Type", "application/json; charset=utf-8"); var rspResult = ResultCode.Fail.JsonR("提供的令牌无效或已过期"); await context.Response.WriteAsync(rspResult.ToJson()); } /// <summary> /// 登录后返回401 /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task Res500Async(HttpContext context) { context.Response.StatusCode = 500; // context.Response?.Headers?.Add("Content-Type", "application/json; charset=utf-8"); var rspResult = ResultCode.Fail.JsonR("服务器内部错误"); await context.Response.WriteAsync(rspResult.ToJson()); } }
-
-
注册 :在程序的配置文件中,通过
app.UseMiddleware<T>()
方法注册中间件,注册顺序决定了中间件在管道中的执行顺序。例如:-
//自定义中间件,所有请求都使用此中间件 app.UseMiddleware<TokenMiddleWare>();
- 也可以针对特定路径注册中间件:
-
//自定义中间件,以/WeatherForecast开头的请求使用此中间件 app.Map("/WeatherForecast", productapp => { productapp.UseMiddleware<TokenMiddleWare>(); });
-
(二)过滤器
-
定义 :创建一个实现相应过滤器接口(如
IActionFilter
)的类,在其中编写过滤逻辑。例如,以下是一个记录方法执行时间的过滤器定义:-
/// <summary> /// 方法执行筛选器(同步) /// </summary> public class LoggingActionFilter : IActionFilter { ILogger<LoggingActionFilter> _logger; /// <summary> /// /// </summary> /// <param name="logger"></param> public LoggingActionFilter(ILogger<LoggingActionFilter> logger) { _logger = logger; } /// <summary> /// 记录方法开始执行时间 /// </summary> /// <param name="context"></param> public void OnActionExecuting(ActionExecutingContext context) { _logger.LogInformation($"Action '{context.ActionDescriptor.DisplayName}' is executing."); return; } /// <summary> /// 记录方法执行完成时间 /// </summary> /// <param name="context"></param> public void OnActionExecuted(ActionExecutedContext context) { _logger.LogInformation($"Action '{context.ActionDescriptor.DisplayName}' executed."); return; } }
-
-
注册 :通过服务容器注册过滤器,例如在
AddControllers
方法中添加过滤器:-
//注册 MVC 控制器相关的服务,包括模型绑定、验证、格式化等功能。它还会隐式注册路由服务。 builder.Services.AddControllers(options => { options.Filters.Add<LoggingActionFilter>(); //添加过滤器(筛选器) })
-
(三)属性
-
定义 :使用
Attribute
类创建自定义属性,通过AttributeUsage
特性指定属性的适用范围。例如,以下是一个禁用 Token 检查的属性定义:-
/// <summary> /// 禁用token校验属性过滤器 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class SkipTokenAttribute: Attribute { }
-
-
标记 :在控制器或方法上使用定义好的属性,以实现特定的功能。例如:
-
[HttpGet(Name = "GetWeatherForecast")] [SkipToken] public IEnumerable<WeatherForecast> Get() { // return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }
-
-
使用 :在中间件或其他需要的地方,通过反射等方式检测方法是否标记了特定属性,从而决定是否执行相应逻辑。例如,在 Token 中间件中检测是否标记了
SkipTokenAttribute
属性:-
/// <summary> /// 中间件调用 /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public async Task InvokeAsync(HttpContext context, RequestDelegate next) { try { //前逻辑处理 // 获取当前请求的Endpoint var endpoint = context.GetEndpoint(); var skiptoken= endpoint?.Metadata.OfType<SkipTokenAttribute>().Any(); if (skiptoken == true) //未标记禁用token检查 { if (!_tokenService.CheckToken(context)) //校验token有效性,token从header中解析获取 { _ = Res401Async(context); //校验失败,返回401错误 return; } } //进入下一个中间件 await next(context); //后逻辑处理 } catch (Exception ex) { _ = Res500Async(context); //处理异常,返回服务器500错误 } }
-
总结
在 .NET Web 框架中,中间件适用于全局处理逻辑,过滤器聚焦于控制器或方法层面,而属性则为代码实体提供声明式的行为定制手段。在实际开发中,合理搭配使用这三者,能够打造出高性能、高可维护性的 Web 应用。