首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring WebClient :重试中的调用方法

Spring WebClient :重试中的调用方法
EN

Stack Overflow用户
提问于 2020-10-14 14:05:57
回答 1查看 1.8K关注 0票数 2

我一直在寻找以下用例的解决方案,但没有成功,我希望有人能帮助我:

假设以下用例。我需要调用customer (customerApi),这个Api需要一个Bearer令牌,当我调用customerApi时它可能已经过期了。如果令牌已过期,customerApi将返回一个401响应。

我想做的是,如果我收到一个401并调用该方法来获得一个新的Bearer令牌,那么只重试一次。如果重试仍然返回401,则需要抛出一个Exception

获取Bearer令牌的方法:

代码语言:javascript
复制
private String getToken() {
    return oAuthService.getToken();
}

并使用webClient调用customerApi (customerWebClient是用WebClient.Builder创建的bean ):

代码语言:javascript
复制
public Customer getCustomerById(String customerId, String token) {
        return customerWebClient.get()
            .uri("myurl/customers/{customerId}, customerId)
            .headers(httpHeaders -> {
                httpHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer " + token);
            })
            .retrieve()
            .bodyToMono(Customer.class)
            .onErrorResume(WebClientResponseException.NotFound.class, notFound ->
                        Mono.error(new MyCustomException()))
            .block();
    }

retryWhen似乎只能用于升级超时。所以我希望有人知道如何实现这个用例^^。

(谢谢你的帮助:)

编辑:

我尝试使用来自reactor-extrareactor-extra,但是这个包中的好的旧retryWhen现在被废弃了(基于:Adding a retry all requests of WebClient的解决方案)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-10-20 18:29:19

该方法

代码语言:javascript
复制
public final Mono<T> retryWhen(Function<Flux<Throwable>, ? extends Publisher<?>> whenFactory)

已被否决,现在首选的方法是

代码语言:javascript
复制
public final Mono<T> retryWhen(Retry retrySpec)

因此,您可以将代码修改为类似于这样的内容,使其与新的retryWhen一起工作。

代码语言:javascript
复制
public Customer getCustomerById(String customerId, String token) {

    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + token);

    final RetrySpec retrySpec = Retry.max(1).doBeforeRetry(
        retrySignal -> headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + someTokenGetterMethod()))
        .filter(throwable -> throwable.getClass() == Unauthorized.class);

    return Mono.defer(() -> webClient.get().uri("myurl/customers/{customerId}, customerId")
        .headers(httpHeaders -> httpHeaders.addAll(headers))
        .retrieve()
        .bodyToMono(Customer.class))
        .retryWhen(retrySpec)
        .onErrorResume(WebClientResponseException.NotFound.class,
            notFound -> Mono.error(new MyCustomException()))
        .block();
}

下面是一个使用https://httpbin.org/的工作示例

代码语言:javascript
复制
public CommandLineRunner commandLineRunner() {

    HttpHeaders headers = new HttpHeaders();

    final RetrySpec retrySpec = Retry.max(1).doBeforeRetry(
        retrySignal -> headers.add("Authorization", "Bearer 1234")).filter(
        throwable -> throwable.getClass() == Unauthorized.class);

    return args -> Mono.defer(() -> webClient.get().uri("https://httpbin.org/bearer")
        .headers(httpHeaders -> httpHeaders.addAll(headers)).retrieve().toEntity(Map.class)
        .retryWhen(retrySpec)
        .subscribe(objectResponseEntity -> System.out
            .println("objectResponseEntity = " + objectResponseEntity.getBody()));
}

此外,我不认为在重试添加授权令牌时试图操作头的方式是实现这一目标的正确方法。你必须想出一个更好的解决方案/设计。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64355088

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档