spring OncePerRequestFilter 作用

发布于:2025-05-01 ⋅ 阅读:(25) ⋅ 点赞:(0)

概要

OncePerRequestFilter 是 Spring Web 提供的一个抽象滤器基类,用于保证在一次 HTTP 请求的整个分派过程中,该滤器仅执行一次,无论该请求经历了多少次内部转发(forward)、包含(include)或错误/异步分派。它通过在请求属性中打标记来判断自身是否已执行过,并提供了一个只需关注业务逻辑的 doFilterInternal 方法,同时支持子类根据需要决定是否在错误或异步 dispatch 中跳过过滤。


核心作用与工作原理

  1. 保证单次执行

  2. 简化子类实现

  3. 异步与错误分派控制


关键方法

  • doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    实现了对“已过滤”标记的检查与设置,并最终调用 doFilterInternal(...) 或直接跳过。

  • protected abstract void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
    子类在此方法中编写实际的过滤逻辑(如认证、日志、头处理等),执行完成后必须调用 filterChain.doFilter(request, response) 以继续后续处理。

  • protected boolean shouldNotFilterAsyncDispatch()
    返回 true 时会跳过在异步 dispatch 场景下的过滤,默认 false

  • protected boolean shouldNotFilterErrorDispatch()
    返回 true 时会跳过在错误 dispatch 情形下的过滤,默认 false


常见使用场景

  1. Spring Security 定制过滤器
    Authentication、CSRF、Header 处理等安全相关过滤器通常继承自 OncePerRequestFilter,确保安全检查仅执行一次,而不会因内部转发而重复认证 (Architecture :: Spring Security)。

  2. 请求日志与限流
    在高并发场景下,通过自定义 OncePerRequestFilter 打印请求日志、记录链路或进行请求计数,避免重复记录导致数据冗余。

  3. 统一异常处理或上下文初始化
    为每次请求初始化线程上下文、数据库连接或绑定 MDC(Mapped Diagnostic Context),并在请求结束前清理资源。


注意事项

  • 务必调用 filterChain.doFilter
    若漏写此调用,将导致后续过滤器及 Servlet 无法执行。

  • 异步请求处理
    对于启用了 Servlet 3.0+ 异步支持的应用,如不希望在异步回调线程再次执行过滤逻辑,可重写 shouldNotFilterAsyncDispatch() 返回 true

  • 标记名称冲突
    默认过滤标记名称与具体滤器实例名称相关,如有定制需求可重写 getAlreadyFilteredAttributeName()

  • 注入与依赖
    若在 doFilterInternal 中需注入 Spring Bean,请确保过滤器已通过 Spring 容器管理(如注册为 @Component 或在 FilterRegistrationBean 中声明),否则可能拿不到依赖(详见 StackOverflow 讨论) (Dependency Injection into Spring Servlet context ... - Stack Overflow)。