当前位置: 首页 > news >正文

spring OncePerRequestFilter 作用

概要

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


核心作用与工作原理

  1. 保证单次执行

    • 默认情况下,OncePerRequestFilter 会在过滤链开始时检查请求属性(属性名由 getAlreadyFilteredAttributeName() 确定),若标记已存在则跳过,未标记则执行并打标记,确保同一次请求不会重复过滤 (OncePerRequestFilter (Spring Framework 6.2.6 API), OncePerRequestFilter - Spring)。

  2. 简化子类实现

    • 子类只需重写 doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain),聚焦业务逻辑,不必关心重复执行的问题 (OncePerRequestFilter (Spring Framework 6.2.6 API))。

  3. 异步与错误分派控制

    • 默认 OncePerRequestFilter 在普通、ERROR、ASYNC 三种 dispatch 类型中均执行过滤;子类可通过重写 shouldNotFilterAsyncDispatch()shouldNotFilterErrorDispatch() 来排除异步或错误分派情形下的执行 (OncePerRequestFilter - Spring, Add the ability for OncePerRequestFilter to determine if it should ...)。


关键方法

  • 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)。

http://www.xdnf.cn/news/145459.html

相关文章:

  • Zynq 7000的PS侧DDR3地址范围及相关信息
  • 《使用 Cesium 加载静态热力图显示的实现步骤》
  • 【LeetCode 热题 100】滑动窗口最大值 / 最小覆盖子串 / 轮转数组 / 缺失的第一个正数
  • 如何创建和推广高质量内容:SEO与内容营销的成功指南
  • Low Poly 风格 | 飞机飞行可视化系统
  • Vue3 上传后的文件智能预览(实战体会)
  • React 实现爱心花园动画
  • 漏洞管理体系:从扫描评估到修复验证的全生命周期实践
  • 3.4 Spring Boot异常处理
  • SkyWalking 安装与使用详细总结
  • No version of NDK matched the requested version21.0.6113669
  • uniapp 常用开发技巧与实战指南
  • 安装openstack-keystone教程
  • Golang | HashMap实现原理
  • AI视频技术赋能幼儿园安全——教师离岗报警系统的智慧守护
  • Node.js 包管理工具介绍
  • 30分钟算法题完成
  • Node.js 开发项目
  • [吾爱出品] 【键鼠自动化工具】支持识别窗口、识图、发送文本、按键组合等
  • go:无刷新前后端交互设计
  • 九、小白如何用Pygame制作一款跑酷类游戏(添加前进小动物作为动态障碍物)
  • 【含文档+PPT+源码】基于微信小程序连锁药店商城
  • 永久缓存 Git 凭证
  • 【playwright】 page.wait_for_timeout() 和time.sleep()区别
  • Unity | AmplifyShaderEditor插件基础(第三集:颜色的计算)
  • 驱动开发硬核特训 · Day 19:字符设备驱动实战(控制 LED)
  • MP自动填充之MetaObjectHandler核心方法解析
  • MATLAB技巧——平滑滤波,给出一定的例程和输出参考
  • openGauss手工配置主备
  • Java大师成长计划之第3天:Java中的异常处理机制