问题描述
我一直在寻找以下用例的解决方案,但没有成功,希望有人可以提供帮助:
假定以下用例。我需要调用客户Api(customerApi
),并且此api需要一个Bearer
令牌,当我调用customerApi
时该令牌可能已过期。如果令牌已过期,则customerApi
返回401
响应。
我想做的是仅在收到401
后重试一次,然后调用该方法以获取新的Bearer
令牌。如果重试仍然返回401
,则需要抛出Exception
private String getToken() {
return oAuthService.getToken();
}
然后使用webClient
来调用customerApi
(customerWebClient
是使用WebClient.Builder
创建的bean):
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
仅可用于升级超时。所以我希望有人知道如何实现此用例^^
感谢您的帮助:)
编辑:
我尝试使用retrywhen(Retry.onlyIf(...))
中的reactor-extra
,但此软件包中的旧版本retrywhen
已过时(基于Adding a retry all requests of WebClient的解决方案)
解决方法
方法
public final Mono<T> retryWhen(Function<Flux<Throwable>,? extends Publisher<?>> whenFactory)
已被弃用,现在首选的方法是
public final Mono<T> retryWhen(Retry retrySpec)
因此,您可以将代码修改为类似的格式,以使其与新的retryWhen
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();
}
的有效示例
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()));
}
此外,我认为您尝试重新尝试添加授权令牌时尝试操作标头的方法不是实现此目的的正确方法。您必须提出更好的解决方案/设计。