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

如何捕获阻塞式WebClient GET请求onStatus中的自定义异常?

解决WebClient block()调用时自定义异常被ReactiveException包装的问题

我完全懂你遇到的这个坑——用WebClient做阻塞调用时,明明在onStatus里抛了自定义的PersonNotFoundException,结果外层catch块却抓不到,反而被Reactor的ReactiveException给包了一层,导致程序直接终止。这其实是Reactor框架的设计逻辑:block()方法只会抛出RuntimeException或Error,如果你的自定义异常是受检异常(继承自Exception而非RuntimeException),就会被自动包装进ReactiveException里。

下面给你几个实用的解决办法:

方法1:将自定义异常改为非受检异常(推荐)

响应式编程生态里普遍使用非受检异常,所以直接让PersonNotFoundException继承RuntimeException就行,这样Reactor就不会额外包装它了:

public class PersonNotFoundException extends RuntimeException {
    public PersonNotFoundException(String message) {
        super(message);
    }
}

修改后你的原有客户端代码不需要任何改动,外层的catch块就能直接捕获到PersonNotFoundException了。

方法2:手动unwrap异常(如果必须保留受检异常)

如果你因为业务约束必须让PersonNotFoundException是受检异常,那可以在调用block()之后,手动提取被包装的原始异常:

public PersonDto getPersonDetails(String lastName) throws PersonNotFoundException {
    try {
        return webClient.get()
                .uri(personEndpoint + "/{lastName}", lastName)
                .retrieve()
                .onStatus(status -> status.equals(HttpStatus.NO_CONTENT), 
                          clientResponse -> Mono.error(new PersonNotFoundException("Person " + lastName + " Not Found")))
                .bodyToMono(PersonDto.class)
                .block();
    } catch (ReactiveException e) {
        // 用Reactor工具方法剥开异常包装
        Throwable originalException = Exceptions.unwrap(e);
        if (originalException instanceof PersonNotFoundException) {
            throw (PersonNotFoundException) originalException;
        }
        // 非目标异常则继续抛出原包装异常
        throw e;
    }
}

这里用到的Exceptions.unwrap()是Reactor提供的工具方法,能帮你层层解开嵌套的Reactor异常,拿到最原始的自定义异常。

方法3:用blockOptional()转换空结果触发异常(另一种思路)

你也可以把204响应转换成空Mono,再通过blockOptional()的空值判断来抛出自定义异常,完全绕开Reactor的异常包装逻辑:

public PersonDto getPersonDetails(String lastName) throws PersonNotFoundException {
    return webClient.get()
            .uri(personEndpoint + "/{lastName}", lastName)
            .retrieve()
            .onStatus(status -> status.equals(HttpStatus.NO_CONTENT), 
                      clientResponse -> Mono.empty()) // 将204转为空Mono
            .bodyToMono(PersonDto.class)
            .blockOptional()
            .orElseThrow(() -> new PersonNotFoundException("Person " + lastName + " Not Found"));
}

验证效果

修改后,你的调用代码里的catch块就能正常捕获到目标异常了:

PersonDto personDto = null;
try {
    personDto = personServiceCLient.getPersonDetails("Smith");
} catch (PersonNotFoundException e) {
    // 这里就能正常执行204对应的自定义处理逻辑了
    System.out.println("处理人员不存在异常:" + e.getMessage());
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:48:39