You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 04:53:20