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

@Async方法调用JwtTokenUtils抛出No thread-bound request found异常求助

问题:@Async注解方法中调用JwtTokenUtils抛出No thread-bound request found异常

我在使用JwtTokenUtils工具类获取token时发现,普通服务类中调用正常,但在带有@Async注解的服务类方法里调用时,会抛出java.lang.IllegalStateException: No thread-bound request found异常。两个类均通过@Autowired注入JwtTokenUtils,唯一区别就是目标服务方法是否加了@Async注解。

普通服务类在方法启动初期调用工具类即可正常获取结果,而带@Async的服务类是在业务校验后发起API调用时才调用该工具类,期望实现所有场景下都能正常获取token。


抛出异常的代码片段

public String getAuthorizationHeader() {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
    if(request != null) {
        return request.getHeader("Authorization");
    } else {
        throw new BadRequestException(ErrorConstants.INVALID_REQUEST);
    }
}

异常详情

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.


完整JwtTokenUtils类代码

@Component
public class JwtTokenUtils {
    private final Logger log = LoggerFactory.getLogger(JwtTokenUtils.class);

    @Value("${security.jwt.token.secret-key:secret-key}")
    private String secretKey;

    @PostConstruct
    protected void init() {
        secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
    }

    public String getToken() {
        String authToken = getAuthorizationHeader();
        
        if (authToken != null && authToken.startsWith("Bearer ")) {
            return authToken.substring(7);
        } else {
            throw new BadRequestException(ErrorConstants.INVALID_REQUEST, "No/Invalid Authorization Token Provided");
        }
    }

    public String getAuthorizationHeader() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        if(request != null) {
            return request.getHeader("Authorization");
        } else {
            throw new BadRequestException(ErrorConstants.INVALID_REQUEST);
        }
    }
}

原因分析

@Async方法会在独立的线程中执行,而RequestContextHolder默认仅将请求上下文绑定在处理请求的原始线程中,异步线程无法继承该上下文,因此调用currentRequestAttributes()时找不到请求对象,抛出异常。


解决办法

方法1:配置请求上下文继承

在Spring Boot中,自定义异步任务执行器,让异步线程继承原始线程的请求上下文:

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        // 核心配置:绑定原始请求上下文到异步线程
        executor.setTaskDecorator(runnable -> {
            RequestAttributes context = RequestContextHolder.currentRequestAttributes();
            return () -> {
                try {
                    RequestContextHolder.setRequestAttributes(context);
                    runnable.run();
                } finally {
                    RequestContextHolder.resetRequestAttributes();
                }
            };
        });
        executor.initialize();
        return executor;
    }
}

配置后,异步线程可携带原始请求上下文,调用JwtTokenUtils时能正常获取请求头。

方法2:手动传递token(更推荐)

依赖线程上下文的方式存在隐患(如异步任务执行过长导致上下文被清理),更稳妥的方式是在调用异步方法时直接传递token:

  1. 修改异步服务方法,接收token参数:
@Async
public void asyncBusinessMethod(String token) {
    // 业务校验后直接使用传入的token发起API调用
    String validToken = jwtTokenUtils.validateToken(token);
    // 后续业务逻辑
}
  1. 在原始请求线程中获取token并传递:
// 先在主线程获取token
String token = jwtTokenUtils.getToken();
// 调用异步方法时传入
asyncService.asyncBusinessMethod(token);
  1. 为JwtTokenUtils新增token校验方法,统一逻辑:
public String validateToken(String token) {
    if (token != null && token.startsWith("Bearer ")) {
        return token.substring(7);
    } else {
        throw new BadRequestException(ErrorConstants.INVALID_REQUEST, "No/Invalid Authorization Token Provided");
    }
}

方法3:配置RequestContextFilter(传统Spring MVC项目)

在web.xml中配置过滤器,允许子线程继承请求上下文:

<filter>
    <filter-name>requestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
    <init-param>
        <param-name>threadContextInheritable</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>requestContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

内容的提问来源于stack exchange,提问作者Shalini Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 11:27:35