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

Spring Webflux Webclient记录错误状态码与消息并返回原数据

问题描述

需求:通过Spring Webflux WebClient携带MyPojo请求体调用外部API,始终返回原MyPojo;当外部API返回非200状态码时,记录错误状态码和错误消息体(不抛出异常),仍返回原请求的MyPojo。

尝试的代码:

public Flux<MyPojo> question (Flux<MyPojo> myPojoFlux) {
    return myPojoFlux.flatMap(myPojo -> webClient.post().bodyValue(myPojo).exchangeToMono(clientResponse -> logStatusCodeAndErrorBodyWhenNotStatusOk(clientResponse, myPojo)));
}

private Mono<MyPojo> logStatusCodeAndErrorBodyWhenNotStatusOk(final ClientResponse clientResponse, final MyPojo myPojo) {
    if (200 != clientResponse.statusCode().value()) {
        //Not able to get the error message body :'(
        LOGGER.warn("The third party API responded status code {} with error message body {} for this request payload {}", clientResponse.statusCode().value(), myPojo, null);
        //Note: I do not want to throw any exception here
    }
    //return the original payload mypojo object
    return Mono.just(myPojo);
}

曾尝试onError、onStatus方法但无效,当前问题:现有实现可获取错误状态码,但无法获取错误消息体,如何实现同时记录两者且返回原请求数据?

解决方案

核心问题是未主动读取非200响应的消息体,WebClient的响应体为流式数据,必须通过bodyToMono或bodyToFlux主动订阅才能获取内容。修改后的代码如下:

public Flux<MyPojo> question(Flux<MyPojo> myPojoFlux) {
    return myPojoFlux.flatMap(myPojo -> 
        webClient.post()
            .bodyValue(myPojo)
            .exchangeToMono(clientResponse -> {
                HttpStatusCode statusCode = clientResponse.statusCode();
                if (statusCode.is2xxSuccessful()) {
                    // 成功时直接返回原请求对象
                    return Mono.just(myPojo);
                } else {
                    // 读取错误响应体,记录日志后返回原请求对象
                    return clientResponse.bodyToMono(String.class)
                        .doOnNext(errorBody -> 
                            LOGGER.warn("第三方API返回错误状态码: {}, 错误消息体: {}, 请求参数: {}", 
                                statusCode.value(), errorBody, myPojo)
                        )
                        .thenReturn(myPojo); // 无论错误体读取结果如何,都返回原对象
                }
            })
    );
}

关键说明

  1. 读取错误体:通过clientResponse.bodyToMono(String.class)读取错误响应的文本内容,如果第三方API返回结构化错误(如JSON),可将String.class替换为对应的错误DTO类(如ApiError.class),方便解析错误字段。
  2. 不中断流:使用thenReturn(myPojo)确保无论错误体读取是否成功,最终都返回原请求的MyPojo,不会中断流的执行。
  3. 逻辑复用(可选):若需复用日志逻辑,可提取为单独方法:
private Mono<MyPojo> handleNonSuccessResponse(ClientResponse clientResponse, MyPojo myPojo) {
    return clientResponse.bodyToMono(String.class)
        .doOnNext(errorBody -> 
            LOGGER.warn("第三方API返回错误状态码: {}, 错误消息体: {}, 请求参数: {}", 
                clientResponse.statusCode().value(), errorBody, myPojo)
        )
        .thenReturn(myPojo);
}

之后在exchangeToMono中调用即可:

.exchangeToMono(clientResponse -> {
    if (clientResponse.statusCode().is2xxSuccessful()) {
        return Mono.just(myPojo);
    } else {
        return handleNonSuccessResponse(clientResponse, myPojo);
    }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 13:03:35