Spring Boot REST资源服务器自定义Okta用户过滤器被调用两次的问题
问题解答
首先修正你代码里的两处明显问题:
- 过滤器的
doFilterInternal方法里,你写的filterChain.doFilter(httpServletRequest, httpServletResponse);属于粘贴笔误,实际应该用方法入参的request和response,否则代码无法编译通过。 - 你同时给
AppUserRegistrationFilter加了@Component注解,又在安全配置里手动new了一个实例加入过滤器链。虽然OncePerRequestFilter会通过请求属性标记避免同一请求重复执行逻辑,但这种写法属于冗余注册,最好二选一:要么去掉@Component完全手动管理,要么去掉手动new的逻辑,直接注入Spring容器里的实例。
触发两次调用的核心原因
绝大多数这类场景,都是前端在进入消息板块时并行发起了两个携带JWT令牌的受保护请求。常见的情况是:
- 第一个请求拉取当前登录用户的个人信息
- 第二个请求拉取消息列表数据
两个请求都需要经过BearerTokenAuthenticationFilter完成JWT认证,自然都会触发你加的AppUserRegistrationFilter。第一次执行时数据库里还没有对应用户,走新增逻辑,同时写入注册时间和最后访问时间;第二次执行时用户已经存在,走更新逻辑,把最后访问时间刷新为第二次请求的时间,因此两个时间会出现细微差异。
该行为是否正常
只要确认是两个独立的业务请求触发的,这个行为完全正常,符合你代码的设计预期——每次受保护请求都会更新用户的最后访问时间。
快速排查方式
打开浏览器开发者工具的网络面板,过滤XHR/Fetch请求,进入消息板块时查看是否存在两个携带Authorization头的请求发给后端,即可快速确认原因。
其他少见可能原因
如果网络面板只有一个请求,再排查以下情况:
- 后端接口返回了3xx重定向,导致浏览器自动发起第二次请求
- 前端HTTP客户端配置了请求失败重试策略
- 开启了Spring Boot DevTools热部署,类加载冲突导致过滤器被重复注册
可选优化建议
- 现在的逻辑每次请求都要执行一次数据库查询和写入,高并发场景下会带来不必要的数据库压力,可以考虑引入本地缓存(比如Caffeine)缓存用户信息,减少数据库操作频率。
- 如果不需要每次请求都刷新最后访问时间,可以按用户维度加个时间窗口,比如10分钟内不重复更新,进一步降低数据库写入次数。
内容的提问来源于stack exchange,提问作者Luca Bonetti
相关产品推荐
相关产品推荐

