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

Spring WebClient全局配置404返回Optional.empty()报错求解

问题原因

你在ExchangeFilterFunction的响应处理器中直接返回Mono.empty()是不合法的。WebClient的响应处理链要求必须要么输出一个有效的ClientResponse实例,要么抛出异常;返回空Mono会让底层客户端认为响应未正常完成,从而触发IllegalStateException。

解决方案

最简洁的方式是使用WebClient原生提供的defaultStatusHandler方法,全局配置404状态的处理逻辑,完全匹配你单独调用时的效果:

return WebClient.builder()
        .defaultStatusHandler(
                HttpStatus.NOT_FOUND::equals,
                clientResponse -> {
                    // 必须消费404响应的body,避免连接资源泄漏
                    return clientResponse.bodyToMono(Void.class).then(Mono.empty());
                }
        )
        .build();

逻辑说明

  • defaultStatusHandler第一个参数指定要拦截的状态码(这里精准匹配404)
  • 第二个参数是处理逻辑:先通过bodyToMono(Void.class)消费掉响应体(防止连接资源泄漏),再返回Mono.empty()。后续调用bodyToMono(User.class)时会得到空Mono,最终blockOptional()会返回Optional.empty(),和你单独实现的逻辑完全一致。

备选方案(基于ExchangeFilterFunction)

如果一定要用ExchangeFilterFunction实现,不能直接返回空Mono,需要先消费响应体再抛出异常,之后全局捕获该异常返回空Mono:

Function<ClientResponse, Mono<ClientResponse>> responseProcessor = clientResponse -> {
    HttpStatusCode status = clientResponse.statusCode();
    if (HttpStatus.NOT_FOUND.equals(status)) {
        // 消费响应体后抛出404异常
        return clientResponse.bodyToMono(Void.class)
                .then(Mono.error(new WebClientResponseException(
                        status.value(),
                        status.getReasonPhrase(),
                        clientResponse.headers().asHttpHeaders(),
                        null,
                        null,
                        null
                )));
    }
    if (status.is4xxClientError() || status.is5xxServerError()) {
        return clientResponse.createError();
    }
    return Mono.just(clientResponse);
};

return WebClient.builder()
        .filter(ExchangeFilterFunction.ofResponseProcessor(responseProcessor))
        .build();

调用时(或全局添加onErrorResume):

return webClient.get()
        .uri(buildUrl(username))
        .retrieve()
        .bodyToMono(User.class)
        .onErrorResume(WebClientResponseException.class, e -> 
                HttpStatus.NOT_FOUND.equals(e.getStatusCode()) ? Mono.empty() : Mono.error(e)
        )
        .blockOptional();

显然第一种defaultStatusHandler的方式更简洁,无需在每个调用中重复编写异常处理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:03:23