Java Webflux Webclient使用不同的URL重试

Java Webflux Webclient使用不同的URL重试,java,spring,spring-boot,spring-webflux,Java,Spring,Spring Boot,Spring Webflux,我正在使用webclient进行rest调用,我需要的是,如果主URL第n次失败,请在辅助URL上进行下一次重试。请在下面找到我正在使用的逻辑的示例代码。但是,一旦他客户机被创建,我们似乎就无法更改URL,即使我更改了URL,它也不会生效,并且仍然会向初始URL发出请求 ClientHttpConnector connector;//initiate WebClient webClient = WebClient.builder().clientConnector(connector).buil

我正在使用webclient进行rest调用,我需要的是,如果主URL第n次失败,请在辅助URL上进行下一次重试。请在下面找到我正在使用的逻辑的示例代码。但是,一旦他
客户机
被创建,我们似乎就无法更改URL,即使我更改了URL,它也不会生效,并且仍然会向初始URL发出请求

ClientHttpConnector connector;//initiate
WebClient webClient = WebClient.builder().clientConnector(connector).build();
WebClient.RequestBodyUriSpec client = webClient.post();

client.uri("http://primaryUrl/").body(BodyInserters.fromObject("hi")).retrieve().bodyToMono(String.class).retryWhen(Retry.anyOf(Exception.class)
                    .exponentialBackoff(Duration.ofSeconds(2), Duration.ofSeconds(10)).doOnRetry(x ->
                    {
                        if (x.iteration() == 2) {
                            client.uri("http://fail_over_url/");//this does not work
                        }
                    })
                    .retryMax(2)).subscribe(WebClientTest::logCompletion, WebClientTest::handleError);
有没有办法在重试周期中间更改URL

但似乎一旦客户端创建,我们就无法更改URL

你不能——它是不可变的

即使我更改了URL,它也不会生效

您实际上并没有更改URL。看看
uri()
方法-它返回一个新实例,并设置了一个uri。由于您没有对该新实例执行任何操作,因此不会发生任何事情(如预期的那样)

我可能建议的方法是创建一个单独的方法来形成并返回您的基本
WebClient
publisher:

private Mono<String> fromUrl(String url) {
    return WebClient.builder().clientConnector(connector).build()
            .post()
            .body(BodyInserters.fromValue("hi"))
            .uri(url)
            .retrieve()
            .bodyToMono(String.class);
}
…它将尝试
/400
3次,然后尝试
/500
5次,然后尝试
/200
最多7次(但除非它关闭,否则第一次尝试时当然会返回。)

请注意,上面的示例使用了最新版本的reactor core,它内置了重试功能,而不是reactor插件中的重试功能。将其转换为reactor插件功能应该相当简单


这并不是严格地在相同的重试周期中更改URL,而是将请求链接在一起,并为每个请求配置重试次数。然后,这允许您在不同的URL上设置不同的重试策略,如果您不一定希望重试从上一点“继续”,这将是有利的(例如,对于一个新的URL,将回退设置为1秒是有意义的)。

您使用的是哪种版本的Reactor+插件?由于静态引用和错误的方法签名,我的ide中出现了大量错误。另外,
connector
来自fromUrl的哪个位置,它是否不需要传入,或者您是否假设它在类中是全局的?@123最新版本的reactor core-不再需要附加组件,包含所有内置的重试功能。(假设连接器是全局的,因为问题并没有在任何地方实例化它,但如果它不是全局的,就很容易改变。)啊,实际上在测试项目中两者都有。看起来额外的是第一个在导入,所以需要完整的路径。此外,我认为OP仍在使用额外功能,因为它们使用的是
anyOf
,这不在核心
重试
@123中,这是一个很好的观点-这将教会我如何快速。。。我会在回答中澄清这一点。谢谢@MichaelBerry,完美的答案。
fromUrl("https://httpstat.us/400").retryWhen(Retry.backoff(2, Duration.ofSeconds(1)))
        .onErrorResume(t -> Exceptions.isRetryExhausted(t), t -> fromUrl("https://httpstat.us/500").retryWhen(Retry.backoff(5, Duration.ofSeconds(1))))
        .onErrorResume(t -> Exceptions.isRetryExhausted(t), t -> fromUrl("https://httpstat.us/200").retryWhen(Retry.backoff(7, Duration.ofSeconds(1))))