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

同步模式下Spring WebClient拦截器block()报错的解决方案咨询

问题解决:WebClient拦截器中block()报错的解决方案

问题背景

我们项目用Spring WebClient调用外部API,不需要响应式方案,所以采用同步模式。该外部API需要先授权,再在请求的Authorization头中携带令牌。我们编写了拦截器自动补充令牌,但遇到错误:
block()/blockfirst()/blocklast() are blocking, which is not supported in thread parallel-1

可行解决方案

方案1:改用响应式链式调用(推荐)

WebClient的拦截器ExchangeFilterFunction本身是响应式设计,返回Mono<ClientResponse>,所以别用block()阻塞获取令牌,而是用flatMap把令牌获取和原请求串联成响应式链条,避开线程阻塞限制。

修改后的拦截器代码:

private ExchangeFilterFunction authExchangeFilterFunction() {
    return (request, next) -> {
        // 建议把授权用的WebClient做成Bean,避免每次请求都重新构建
        WebClient authWebClient = WebClient.builder()
                .baseUrl(properties.getBaseUrl())
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                .filter(ExchangeFilterFunctions.basicAuthentication(
                        properties.getAuth().getBasic().getUsername(),
                        properties.getAuth().getBasic().getPassword()
                ))
                .filter(WebclientUtils.exchangeFilterLogRequest())
                .filter(WebclientUtils.exchangeFilterLogResponse())
                .build();

        // 生成授权所需的表单数据(根据实际接口要求调整)
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("grant_type", "client_credentials");
        // 补充其他必要参数...

        // 响应式获取令牌,再继续处理原请求
        return authWebClient.post()
                .uri("/oauth/token")
                .body(BodyInserters.fromFormData(formData))
                .retrieve()
                .bodyToMono(String.class)
                .flatMap(token -> {
                    // 给原请求添加Authorization头(注意格式,通常是Bearer + 令牌)
                    ClientRequest authorizedRequest = ClientRequest.from(request)
                            .header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
                            .build();
                    // 执行后续过滤器和请求
                    return next.exchange(authorizedRequest);
                });
    };
}

方案2:用同步HTTP客户端获取令牌(适配纯同步场景)

如果坚持要用同步逻辑,别在拦截器里用WebClient的block(),改用RestTemplate(Spring官方同步HTTP客户端)来获取令牌——RestTemplate本身就是同步阻塞设计,不会运行在Reactor的线程池中,自然不会触发线程限制。

步骤1:定义用于授权的RestTemplate Bean

@Bean
public RestTemplate authRestTemplate(ApiProperties properties) {
    RestTemplate restTemplate = new RestTemplate();
    // 添加Basic认证拦截器
    restTemplate.getInterceptors().add((req, body, execution) -> {
        String authStr = properties.getAuth().getBasic().getUsername() + ":" + properties.getAuth().getBasic().getPassword();
        String authBase64 = Base64Utils.encodeToString(authStr.getBytes(StandardCharsets.UTF_8));
        req.getHeaders().add(HttpHeaders.AUTHORIZATION, "Basic " + authBase64);
        return execution.execute(req, body);
    });
    return restTemplate;
}

步骤2:修改拦截器代码,注入RestTemplate获取令牌

private final RestTemplate authRestTemplate;
private final ApiProperties properties;

// 通过构造器注入依赖
public YourConfigClass(RestTemplate authRestTemplate, ApiProperties properties) {
    this.authRestTemplate = authRestTemplate;
    this.properties = properties;
}

private ExchangeFilterFunction authExchangeFilterFunction() {
    return (request, next) -> {
        // 生成授权表单数据
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("grant_type", "client_credentials");
        // 补充其他参数...

        // 同步获取令牌
        ResponseEntity<String> tokenResponse = authRestTemplate.postForEntity(
                properties.getBaseUrl() + "/oauth/token",
                formData,
                String.class
        );
        String token = tokenResponse.getBody();

        // 修改原请求并继续执行
        ClientRequest authorizedRequest = ClientRequest.from(request)
                .header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
                .build();
        return next.exchange(authorizedRequest);
    };
}

额外优化建议

不管用哪种方案,都要缓存令牌(注意令牌的过期时间),避免每次请求都调用授权接口浪费资源。可以用Guava Cache或者Spring的@Cacheable注解实现缓存逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:30:40