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

Spring Boot WebClient添加onStatus后调用bodyToMono遇NPE求助

WebClient添加onStatus后调用bodyToMono触发空指针异常的解决办法

我在用Spring Boot WebClient发送POST请求时遇到问题:请求本身能正常执行,但添加onStatus处理HTTP错误码后,调用bodyToMono会抛出空指针异常(NPE);移除onStatus就能正常获取响应。我需要处理所有4xx、5xx错误,以及402、404、500、512这些具体错误码,原代码如下:

Employee createdEmployee = webClient.post()
        .uri("/employees")
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .body(Mono.just(empl), Employee.class)
        .retrieve()
 .onStatus(HttpStatus::isError, clientResponse -> {
          if (clientResponse.statusCode() == HttpStatus.resolve(402)) {
            return Mono.error(new Exception("402"));
          }
          log.error("Error endpoint with status code {}", clientResponse.statusCode());
          if (clientResponse.statusCode() == HttpStatus.resolve(500)) {
            return Mono.error(new Exception("500"));
          }
          if (clientResponse.statusCode() == HttpStatus.resolve(512)) {
            return Mono.error(new Exception("512"));
          }
          return Mono.error(new Exception("Error while processing request"));
        })
        .bodyToMono(Employee.class);

问题原因

触发NPE的核心是:当onStatus匹配到错误状态码时,你直接返回了Mono.error,但没有消费错误响应的body。WebClient要求必须读取完响应体才能完成请求生命周期,未消费的响应体会导致资源泄漏,进而引发空指针这类异常。

修正方案

修改onStatus的处理逻辑,在返回错误信号前,先读取并消费响应体。可以用bodyToMono(Void.class)快速丢弃响应体,也可以根据实际需求解析错误响应内容。

修正后的代码:

Employee createdEmployee = webClient.post()
        .uri("/employees")
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .body(Mono.just(empl), Employee.class)
        .retrieve()
        .onStatus(HttpStatus::isError, clientResponse -> {
            // 先消费响应体,避免资源泄漏和NPE
            return clientResponse.bodyToMono(Void.class)
                    .then(Mono.defer(() -> {
                        HttpStatus status = clientResponse.statusCode();
                        if (status == HttpStatus.PAYMENT_REQUIRED) { // 标准402对应的枚举值
                            return Mono.error(new Exception("402"));
                        } else if (status == HttpStatus.NOT_FOUND) { // 404
                            return Mono.error(new Exception("404"));
                        } else if (status == HttpStatus.INTERNAL_SERVER_ERROR) { // 500
                            return Mono.error(new Exception("500"));
                        } else if (status == HttpStatus.resolve(512)) { // 512非标准状态码,用resolve
                            return Mono.error(new Exception("512"));
                        }
                        log.error("Error endpoint with status code {}", status);
                        return Mono.error(new Exception("Error while processing request"));
                    }));
        })
        .bodyToMono(Employee.class);

额外优化建议

  • 优先使用HttpStatus枚举值(比如HttpStatus.PAYMENT_REQUIRED),比resolve()更可靠,避免返回空值
  • 自定义业务异常类代替通用Exception,方便后续精准捕获和处理
  • 如果服务端返回了结构化错误信息,可以把bodyToMono(Void.class)改成解析错误DTO,将错误详情带到自定义异常中

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 05:15:21