Spring Boot 3中DeferredResult返回401的问题求助
DeferredResult接口返回401而非200,但普通接口正常的问题排查与解决
问题场景
调用返回DeferredResult<ResponseEntity<?>>的接口时,内部已设置返回200状态码,但最终收到401响应;而直接返回ResponseEntity<?>的同类型接口能正常返回200。已设置spring.security.filter.dispatcher-types=request, async, error, forward, include,但问题未解决。
相关代码:
@RequestMapping(path = "/sign-document1", method = RequestMethod.GET) public DeferredResult<ResponseEntity<?>> signFile1(){ DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>(5000L); deferredResult.onTimeout(() -> deferredResult.setErrorResult( ResponseEntity .status(HttpStatus.REQUEST_TIMEOUT) .body("Request timeout!"))); deferredResult.setResult(new ResponseEntity<>(HttpStatus.OK)); return deferredResult; // 实际收到401 }
@RequestMapping(path = "/sign-document2", method = RequestMethod.GET) public ResponseEntity<?> signFile2(){ return new ResponseEntity<>(HttpStatus.OK); // 正常收到200 }
排查与解决步骤
1. 配置SecurityFilterChain支持异步上下文传递
Spring Boot 3 + Spring Security 6中,仅设置dispatcher-types不足以保证异步请求继承认证上下文,需在SecurityFilterChain中显式配置:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 保留原有授权等配置 .authorizeHttpRequests(auth -> auth .requestMatchers("/sign-document1", "/sign-document2").permitAll() // 其他授权规则... ) .securityContext(securityContext -> securityContext .requireExplicitSave(false) // 允许异步请求自动保存/继承SecurityContext ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) ); return http.build(); }
2. 手动传递SecurityContext到异步线程
如果上述配置无效,可尝试在设置DeferredResult结果时手动传递上下文:
@RequestMapping(path = "/sign-document1", method = RequestMethod.GET) public DeferredResult<ResponseEntity<?>> signFile1(){ DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>(5000L); // 保存当前请求的SecurityContext SecurityContext currentContext = SecurityContextHolder.getContext(); deferredResult.onTimeout(() -> { SecurityContextHolder.setContext(currentContext); deferredResult.setErrorResult( ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body("Request timeout!")); }); deferredResult.setResultHandler(result -> { SecurityContextHolder.setContext(currentContext); // 确保结果返回时上下文正确 }); deferredResult.setResult(new ResponseEntity<>(HttpStatus.OK)); return deferredResult; }
3. 检查自定义过滤器的异步支持
若存在自定义过滤器,需确保其支持异步调度,重写shouldNotFilterAsyncDispatch方法返回false:
public class CustomFilter extends OncePerRequestFilter { // ... 其他方法 @Override protected boolean shouldNotFilterAsyncDispatch() { return false; // 允许过滤器处理异步请求 } }
4. 确认版本兼容性
确保Spring Security与Spring Boot 3版本完全对齐,避免版本差异导致的异步处理异常。使用Spring Boot Starter时无需手动指定版本,框架会自动匹配:
<!-- pom.xml --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
内容的提问来源于stack exchange,提问作者Octavia
相关产品推荐
相关产品推荐

