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

嵌套WebClient调用遇阻塞问题:.get()无限等待无响应

问题原因

你遇到的无限等待本质是阻塞操作占用了Reactor事件循环线程,导致整个反应式任务链无法被调度执行。WebFlux基于Reactor的事件循环模型,事件循环线程是异步任务的调度核心,如果在这个线程上调用get()这类阻塞方法,会把线程卡死,后续的getToken()、customWebClient.delete()这些异步任务根本没机会执行;直到超时抛出异常后,线程被释放,任务才开始调度执行。

解决方案

核心思路是避免在事件循环线程上执行阻塞操作,要么全程用反应式编程不阻塞,要么把阻塞操作放到专门的弹性线程池中执行。

方案1:用block()替代toFuture().get(),并切换线程池

直接使用Reactor提供的block()方法获取结果,同时通过subscribeOn切换到弹性线程池,避免阻塞事件循环:

import reactor.core.scheduler.Schedulers;
import org.springframework.http.MediaType;
import reactor.core.publisher.Mono;
import java.util.Map;
import org.springframework.core.ParameterizedTypeReference;

// 切换到弹性线程池执行阻塞获取
Map<String, Object> result = someservice.getToken()
    .flatMap(token -> customWebclient.delete()
        .uri(uriBuilder -> uriBuilder.path("/users")
            .queryParam("id", id)
            .build())
        .headers(headers -> headers.setBearerAuth(token))
        .header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
        .header("Accept", MediaType.APPLICATION_JSON_VALUE)
        .retrieve()
        .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
        .log())
    .subscribeOn(Schedulers.boundedElastic())
    .block();

方案2:保留Future方式,但切换线程池

如果必须用Future,同样需要先切换线程池再转Future:

import reactor.core.scheduler.Schedulers;
import java.util.concurrent.Future;
import java.util.Map;

Future<Map<String, Object>> future = someservice.getToken()
    .flatMap(token -> customWebclient.delete()
        .uri(uriBuilder -> uriBuilder.path("/users")
            .queryParam("id", id)
            .build())
        .headers(headers -> headers.setBearerAuth(token))
        .header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
        .header("Accept", MediaType.APPLICATION_JSON_VALUE)
        .retrieve()
        .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
        .log())
    .subscribeOn(Schedulers.boundedElastic())
    .toFuture();

Map<String, Object> result = future.get();

方案3:全程使用反应式编程(推荐)

如果业务场景允许,尽量不要阻塞,直接返回Mono<Map<String, Object>>,让WebFlux的异步模型处理整个流程,从根本上避免阻塞问题:

// 直接返回Mono,不做阻塞操作
public Mono<Map<String, Object>> deleteUser(String id) {
    return someservice.getToken()
        .flatMap(token -> customWebclient.delete()
            .uri(uriBuilder -> uriBuilder.path("/users")
                .queryParam("id", id)
                .build())
            .headers(headers -> headers.setBearerAuth(token))
            .header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
            .header("Accept", MediaType.APPLICATION_JSON_VALUE)
            .retrieve()
            .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
            .log());
}
补充说明

之前GET方法能正常工作是巧合,本质上同样存在阻塞事件循环的风险,只是某些情况下线程调度刚好没被卡死。WebFlux的设计初衷是异步非阻塞,尽量避免在反应式流程中插入阻塞操作,这是保证性能和稳定性的关键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:05:17