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

Spring WebClient实现非阻塞异步HTTP调用及超时配置

Spring WebClient 非阻塞异步HTTP调用实现方案

你现有代码仅完成了响应式流的组装,未触发实际请求,也缺少非阻塞回调、单请求超时配置,针对两个问题的实现方式如下:

非阻塞读取解析响应(不阻塞业务线程)

Reactor响应式流是懒加载的,只有显式订阅才会真正发起HTTP请求,禁止调用block()、get()这类阻塞方法,否则会让当前业务线程同步等待响应,完全失去异步非阻塞的特性。
正确做法是调用Mono.subscribe()方法注册回调函数:业务线程执行到订阅逻辑时会立刻返回,不会等待HTTP响应;等服务端响应返回、内容解析完成后,会由WebClient绑定的异步线程池调度执行回调逻辑处理结果,请求过程中业务线程不会被占用。
核心代码逻辑:

responseMono.subscribe(
    // 响应正常返回、解析完成后异步执行
    responseJson -> {
        // 此处编写你的响应处理、后续业务逻辑
        System.out.println("收到异步HTTP响应:" + responseJson);
    },
    // 请求失败、解析失败、超时等异常场景异步执行
    error -> {
        // 此处编写异常日志、降级、告警逻辑
        log.error("异步HTTP调用异常", error);
    }
);

为单请求设置独立超时时间

不要修改WebClient全局超时配置,直接在当前请求的响应式流上添加配置即可,有两种常用方式:

  • 快速配置总超时:通过timeout()算子直接设置当前请求的最大等待时长,超时后会自动抛出TimeoutException,被上述异常回调捕获,同时自动释放请求连接:
    Mono<JsonObject> responseMono =  headersSpec.retrieve()
            .bodyToMono(JsonObject.class)
            // 示例设置当前请求总超时为5秒,可按需传入Duration调整时长
            .timeout(Duration.ofSeconds(5));
    
  • 细粒度配置不同阶段超时:如果需要单独设置连接超时、读取超时,可在请求构建阶段传入对应属性:
    Mono<JsonObject> responseMono =  headersSpec
            .httpRequest(request -> {
                ClientHttpRequest clientReq = request.getClientRequest();
                // 单独设置连接超时2秒
                clientReq.addAttribute(ClientHttpRequest.CONNECT_TIMEOUT_ATTR, Duration.ofSeconds(2).toMillis());
                // 单独设置读取响应超时5秒
                clientReq.addAttribute(ClientHttpRequest.READ_TIMEOUT_ATTR, Duration.ofSeconds(5).toMillis());
            })
            .retrieve()
            .bodyToMono(JsonObject.class);
    

完整改造后可用代码

import java.time.Duration;
import java.util.Map;
// 其余依赖按需引入
public void asyncHttp(HTTPMethod method,
                      String url,
                      String body,
                      Map<String, String> headers){

    WebClient.UriSpec<WebClient.RequestBodySpec> uriSpec = webClient.method(method.getMethod());
    WebClient.RequestBodySpec bodySpec = uriSpec.uri(url);
    WebClient.RequestHeadersSpec<?> headersSpec = bodySpec.bodyValue(body);
    for(Map.Entry<String, String> entry : headers.entrySet()){
        headersSpec.header(entry.getKey(), entry.getValue());
    }
    Mono<JsonObject> responseMono =  headersSpec.retrieve()
            .bodyToMono(JsonObject.class)
            // 配置当前请求独立超时
            .timeout(Duration.ofSeconds(5));

    // 非阻塞订阅,业务线程执行到此处立刻返回
    responseMono.subscribe(
            resp -> {
                // 自定义响应处理逻辑
                log.info("异步请求响应:{}", resp);
            },
            err -> {
                // 自定义异常处理逻辑
                log.error("异步请求失败", err);
            }
    );
}

补充说明:如果需要做链路追踪等上下文透传,可以在订阅时通过subscriberContext传入上下文参数,或指定自定义调度器适配线程上下文传递逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:46:03