在 .NET Core Web API 开发中,过滤器(Filter)是实现横切关注点解耦的核心组件。它能在请求处理的不同阶段拦截逻辑,统一处理权限验证、日志记录、异常捕获等通用需求,避免重复代码。本文将详细拆解 .NET Core Web API 内置的 5 类过滤器,分析其执行机制、核心用途,并提供可直接复用的实战示例。
一、过滤器核心概念:什么是过滤器?
过滤器是 .NET Core 提供的请求拦截机制,本质是一套 “钩子(Hook)” 系统,能嵌入请求处理生命周期的关键节点。其核心价值在于:
-
解耦横切关注点:将日志、权限、异常处理等通用逻辑与业务逻辑分离;
-
统一管控:对所有接口或指定接口批量应用通用规则;
-
可扩展性:支持自定义过滤器,满足复杂业务场景。
所有过滤器遵循固定的执行顺序,从请求进入到响应返回,完整流程如下:
授权过滤器 → 资源过滤器 → 模型绑定 → Action 过滤器 → 执行 Action → Action 过滤器 → 结果过滤器 → 执行结果 → 结果过滤器 → 资源过滤器 → 响应返回
若任意阶段抛出异常,将直接触发异常过滤器处理。
二、5 类内置过滤器详解:用途 + 执行时机
1. 授权过滤器(AuthorizationFilter):请求的 “第一道关卡”
核心作用
验证请求是否有权限访问接口,是所有过滤器中执行最早的组件。若验证失败,直接终止请求并返回 401(未授权)或 403(禁止访问),不执行后续逻辑。
内置实现
[Authorize]:标记需要授权的 Action/Controller,依赖IAuthorizationService校验身份(配合 JWT、Cookie 等认证方案)。支持角色、策略等精细化授权,示例:
// 仅 Admin 角色可访问
[Authorize(Roles = "Admin")]
[HttpGet("admin/data")]
public IActionResult GetAdminData() => Ok("管理员数据");
[AllowAnonymous]:允许匿名访问,用于公开接口(如登录、注册),会跳过授权校验:
[AllowAnonymous]
[HttpPost("login")]
public IActionResult Login(string username, string password) => Ok("登录成功");
关键特点
-
仅关注 “是否允许访问”,不处理业务逻辑;
-
无 “执行后” 阶段,验证通过则进入下一个过滤器,失败直接返回;
-
常用场景:登录状态校验、角色权限控制、接口访问白名单。
2. 资源过滤器(ResourceFilter):性能优化与资源管理
核心作用
在授权验证后、模型绑定前执行,主要用于性能优化(如响应缓存)或资源管理(创建 / 释放非线程安全资源)。可直接跳过模型绑定和 Action 执行(如返回缓存结果),大幅提升接口性能。
内置实现
[ResponseCache]:最常用的资源过滤器,设置 HTTP 响应缓存(通过Cache-Control头),减少重复请求开销:
// 缓存响应 30 秒,所有客户端共享缓存
[ResponseCache(Duration = 30, Location = ResponseCacheLocation.Any)]
[HttpGet("public/data")]
public IActionResult GetPublicData() => Ok("公开缓存数据");
- 自定义扩展:通过
IAsyncResourceFilter实现复杂缓存逻辑(如分布式缓存)。
关键特点
-
执行时机早于 Action 过滤器,可干预模型绑定流程;
-
支持 “执行前” 和 “执行后” 两个阶段(资源创建 / 释放);
-
常用场景:接口响应缓存、请求频率限制、非线程安全资源管理。
3. Action 过滤器(ActionFilter):业务逻辑的 “前后置处理器”
核心作用
拦截 Action 方法的执行前后,是最常用的过滤器。依赖模型绑定(执行时参数已绑定完成),可访问和修改 Action 的输入参数与返回值,适用于业务相关的通用逻辑。
内置实现
-
[ValidateModel]:自动校验模型绑定后的对象(如[Required]、[MaxLength]等数据注解),校验失败返回 400 Bad Request。Web API 已默认启用,无需手动添加; -
自定义扩展:通过
IAsyncActionFilter实现日志记录、参数校验扩展等。
实战示例:接口请求 / 响应日志过滤器
public class LogActionFilter : IAsyncActionFilter
{
private readonly ILogger<LogActionFilter> _logger;
// 支持依赖注入(如 ILogger)
public LogActionFilter(ILogger<LogActionFilter> logger)
{
_logger = logger;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Action 执行前:记录请求信息
var actionName = context.ActionDescriptor.DisplayName;
var parameters = JsonSerializer.Serialize(context.Arguments);
_logger.LogInformation($"【请求】接口:{actionName},参数:{parameters}");
// 执行 Action 方法
var resultContext = await next();
// Action 执行后:记录响应信息
if (resultContext.Result is ObjectResult objectResult)
{
var response = JsonSerializer.Serialize(objectResult.Value);
_logger.LogInformation($"【响应】接口:{actionName},结果:{response}");
}
}
}
关键特点
-
可修改 Action 输入(
context.Arguments)和输出(resultContext.Result); -
执行时机:模型绑定后(前)、Action 执行后(后);
-
常用场景:接口日志、参数校验、业务逻辑增强(如数据脱敏)。
4. 异常过滤器(ExceptionFilter):统一异常处理中心
核心作用
捕获请求处理过程中(Action、过滤器、模型绑定等阶段)抛出的未处理异常,统一格式化错误响应(避免返回默认 HTML 错误页),同时记录异常日志。
内置实现
- 自定义扩展:通过
IAsyncExceptionFilter实现全局异常处理,.NET 6+ 推荐全局注册。
实战示例:全局异常过滤器(统一 JSON 错误响应)
public class GlobalExceptionFilter : IAsyncExceptionFilter
{
private readonly ILogger<GlobalExceptionFilter> _logger;
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
{
_logger = logger;
}
public Task OnExceptionAsync(ExceptionContext context)
{
// 记录异常详情(含堆栈信息)
_logger.LogError(context.Exception, "接口执行异常:{Message}", context.Exception.Message);
// 统一返回 RFC 7807 标准格式错误响应
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status500InternalServerError,
Title = "服务器内部错误",
Detail = context.Exception.Message,
Instance = context.HttpContext.Request.Path
};
// 区分业务异常和系统异常(可选)
if (context.Exception is BusinessException businessEx)
{
problemDetails.Status = businessEx.StatusCode;
problemDetails.Title = "业务异常";
}
context.Result = new ObjectResult(problemDetails)
{
StatusCode = problemDetails.Status
};
// 标记异常已处理,避免框架默认处理
context.ExceptionHandled = true;
return Task.CompletedTask;
}
}
// 自定义业务异常(示例)
public class BusinessException : Exception
{
public int StatusCode { get; }
public BusinessException(string message, int statusCode = 400) : base(message)
{
StatusCode = statusCode;
}
}
关键特点
-
仅捕获未处理异常,若已被其他组件处理则不触发;
-
可自定义错误响应格式,提升接口友好性;
-
常用场景:全局异常捕获、错误日志记录、业务异常统一处理。
5. 结果过滤器(ResultFilter):响应的 “最后加工器”
核心作用
拦截 Action 结果的执行前后(仅当 Action 成功执行且返回 IActionResult 时触发),用于格式化响应数据、添加响应头、统一包装结果等。
内置实现
[Produces]:指定响应格式(如application/json),本质是通过结果过滤器设置Content-Type头:
[Produces("application/json")]
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase { ... }
- 自定义扩展:通过
IAsyncResultFilter实现响应统一包装。
实战示例:接口响应统一包装(全局启用)
public class WrapResponseFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// 仅处理 ObjectResult 类型(Web API 默认返回类型)
if (context.Result is ObjectResult objectResult)
{
// 统一包装格式:{ "code": 200, "message": "success", "data": ... }
var response = new
{
Code = context.HttpContext.Response.StatusCode,
Message = "success",
Data = objectResult.Value
};
// 覆盖原始结果
objectResult.Value = response;
objectResult.DeclaredType = response.GetType();
}
// 执行后续逻辑(返回响应)
await next();
}
}
关键特点
-
仅关注
IActionResult的执行,不处理异常; -
可修改响应内容和响应头;
-
常用场景:统一响应格式、响应数据脱敏、添加自定义响应头(如接口版本号)。
三、过滤器注册方式:3 种范围选择
过滤器的注册优先级为:局部(Action/Controller)> 全局,可根据需求选择合适的注册范围。
1. 局部注册(仅作用于单个 Action/Controller)
直接在 Action 或 Controller 上添加过滤器特性,适用于局部特殊需求:
// 作用于单个 Action
[LogActionFilter]
[HttpGet("detail/{id}")]
public IActionResult GetDetail(int id) => Ok($"详情:{id}");
// 作用于整个 Controller(所有 Action 生效)
[WrapResponseFilter]
public class ProductController : ControllerBase { ... }
2. 全局注册(作用于所有 Action)
在 Program.cs 中通过 AddControllers 全局注册,适用于通用规则(如全局异常处理、统一响应包装):
var builder = WebApplication.CreateBuilder(args);
// 添加控制器并注册全局过滤器
builder.Services.AddControllers(options =>
{
options.Filters.Add<GlobalExceptionFilter>(); // 全局异常处理
options.Filters.Add<WrapResponseFilter>(); // 统一响应包装
options.Filters.Add<LogActionFilter>(); // 全局请求日志
});
3. 依赖注入注册(推荐)
若过滤器需要依赖其他服务(如 ILogger、数据库上下文),需先注册过滤器为服务,再全局添加:
// 1. 注册过滤器为作用域服务(Scoped:每个请求创建一个实例)
builder.Services.AddScoped<LogActionFilter>();
builder.Services.AddScoped<GlobalExceptionFilter>();
// 2. 全局添加过滤器(通过类型引用,支持依赖注入)
builder.Services.AddControllers(options =>
{
options.Filters.Add<LogActionFilter>();
options.Filters.Add<GlobalExceptionFilter>();
});
四、过滤器选型指南:按需选择不踩坑
| 过滤器类型 | 核心用途 | 关键场景 | 注意事项 |
|---|---|---|---|
| AuthorizationFilter | 权限验证 | 登录校验、角色 / 权限控制、接口白名单 | 执行最早,失败直接终止请求 |
| ResourceFilter | 性能优化、资源管理 | 响应缓存、请求限流、非线程安全资源管理 | 模型绑定前执行,可跳过 Action 执行 |
| ActionFilter | 业务逻辑增强、日志记录 | 接口日志、参数校验、数据预处理 | 依赖模型绑定,可修改 Action 输入输出 |
| ExceptionFilter | 异常捕获与统一处理 | 全局异常日志、错误响应格式化 | 仅处理未捕获异常,需标记 ExceptionHandled = true |
| ResultFilter | 响应格式化、结果包装 | 统一响应格式、响应头添加、数据脱敏 | 仅处理成功的 IActionResult,不处理异常 |
五、总结
.NET Core Web API 的过滤器体系覆盖了请求处理的全生命周期,通过内置过滤器(如 [Authorize]、[ResponseCache])可快速实现通用需求,通过自定义过滤器可满足复杂业务场景。合理使用过滤器能显著提升代码复用性和可维护性,让开发者更专注于核心业务逻辑。
建议在实际项目中:
-
全局注册
GlobalExceptionFilter和WrapResponseFilter,统一异常处理和响应格式; -
对敏感接口使用
[Authorize]进行权限控制; -
对高频访问的公开接口使用
[ResponseCache]提升性能; -
通过自定义
ActionFilter处理接口日志、参数校验等通用逻辑。