Webflux Pass-Through Http Error:如何将响应异常冒泡传递并携带信息?
如何用ExchangeFilterFunction冒泡传递包含响应体和HTTP状态码的WebClient异常
我明白你现在的痛点:想用WebClient的ExchangeFilterFunction把请求中收到的异常(包含响应体和状态码)冒泡传递,但之前的尝试要么捕获不到错误,要么没法把响应体内容塞进异常里。咱们一步步来解决这个问题。
先分析你之前代码的问题
第一个过滤器不生效的原因:WebClient默认不会把HTTP错误状态码(比如4xx、5xx)转化为
Mono/Flux的错误信号,只会返回一个带有错误状态的ClientResponse。所以你的onErrorMap(MyError.class, ...)根本不会触发——因为没有错误信号产生。第二个代码的问题:你尝试在错误状态时返回一个包含
Flux.error()的ClientResponse,但这种方式下游只有在调用bodyToMono()之类的方法时才会触发错误,而且你没法把实际的响应体内容(比如MyError的字段)传递进去,只是抛出了一个固定消息的RuntimeException。
正确的实现方案
我们需要做的是:检查响应状态码,如果是错误状态,就读取响应体到你的MyError类,然后主动抛出这个异常,这样下游就能捕获到包含完整信息的异常了。
1. 完善你的ExchangeFilterFunction实现
public class MyExchangeFilterFunction implements ExchangeFilterFunction { @Override public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) { return next.exchange(request) .flatMap(clientResponse -> { // 判断是否是HTTP错误状态码 if (clientResponse.statusCode().isError()) { // 读取响应体到MyError对象,然后抛出异常 return clientResponse.bodyToMono(MyError.class) .flatMap(myError -> { // 可以在这里补充一些额外信息,比如请求路径 myError.setPath(request.url().getPath()); return Mono.error(myError); }) // 处理读取响应体失败的情况 .onErrorResume(e -> Mono.error(new RuntimeException("Failed to read error response body", e))); } else { // 正常响应直接返回 return Mono.just(clientResponse); } }); } }
2. 过滤器注册(和你之前的方式一致,确保正确添加)
WebClient webClient = WebClient.builder() .filter(new MyExchangeFilterFunction()) // 其他配置比如baseUrl、codecs等 .build();
3. 下游使用时捕获异常
现在当你用这个WebClient发起请求时,一旦收到错误状态码,过滤器就会抛出MyError异常,你可以在下游捕获并处理:
webClient.get() .uri("/some-api") .retrieve() .bodyToMono(YourResponse.class) .onErrorMap(MyError.class, error -> { // 这里可以拿到error里的status、message、path等信息 System.err.println("HTTP Error: " + error.getStatus() + ", Message: " + error.getMessage()); // 可以选择重新包装异常或者直接抛出 return error; }) .subscribe();
关键说明
- 为什么用
flatMap而不是map?因为读取响应体是异步操作(bodyToMono()返回Mono<MyError>),所以需要用flatMap来处理异步流。 - 一定要处理读取响应体失败的情况(
onErrorResume),避免因为响应体格式不符合MyError导致整个流被中断。
内容的提问来源于stack exchange,提问作者Flavouski
相关产品推荐
相关产品推荐

