Spring WebClient聚合多个401 UNAUTHORIZED错误抛出Exceptions.CompositeException

Spring WebClient aggregates multiple 401 UNAUTHORIZED error to throw Exceptions.CompositeException

当 WebClient 使用错误的令牌异步调用外部 api(具有不同的查询参数)时,前几个 returns 为 401 UNAUTHORIZED 并且控制流以 Exceptions.CompositeException 停止。我们在 WebClient 实例中添加了如下所示的过滤器,用于检查 4xx 和 5xx 响应状态代码以抛出自定义异常

private final ExchangeFilterFunction responseFilter() {
    return ExchangeFilterFunction
            .ofResponseProcessor(response -> response.statusCode().isError() ? error(() -> new CustomException("API Error")) : just(response));

private WebClient buildWebClient(WebClient.Builder builder) {
    return builder
            .filter(responseFilter())
            .build();
}

现在的问题是 CustomException 在第一次调用 returns 时没有抛出错误 (401),而是聚集了一堆调用并抛出 Exceptions.CompositeException。在日志中,我们可以在复合失败之前看到至少 3 或 4 401 UNAUTHORIZED。当第一个失败时,它不会抛出预期的 CustomException 。此 WebClient 调用发生在 Flux.zip 内,我不确定这是否与问题有关。

当使用任何 DelayError 变体运算符时,reactor 会将所有异常(如果超过 1 个)收集到 CompositeException.

Reactor 提供了一个实用方法 Exceptions.unwrapMultiple 如果您只想向上游传播一个子集或单个错误,它可以帮助将复合异常解压缩到可抛出列表中 - java docs

Exceptions.unwrapMultiple

Attempt to unwrap a Throwable into a List of Throwables. This is only done on the condition that said Throwable is a composite exception built by multiple(Throwable...), in which case the list contains the exceptions wrapped as suppressed exceptions in the composite. In any other case, the list only contains the input Throwable (or is empty in case of null input).

例子

下面是一个使用 unwrapMultiple 仅传播 CompositeException.

中的第一个 Throwable 的小示例
    Flux<Object> range = Flux.range(1, 10)
            .flatMapDelayError(i -> Mono.error(new IllegalArgumentException(String.format("Error: %s", i))), 10, 1)
            .onErrorResume(throwable -> Mono.error(Exceptions.unwrapMultiple(throwable).get(0)));
    StepVerifier.create(range)
            .expectError(IllegalArgumentException.class)
            .verify();