I figured this out, which was apparent after seeing retry only works on exceptions, webClient doesn't throw the exception, since the clientResponse object just holds the response, only when bodyTo is called is the exception thrown on http status, so to fix this, one can mimic this behaviour
@Bean(name = "retryWebClient")
public WebClient retryWebClient(WebClient.Builder builder, TokenProvider tokenProvider) {
return builder.baseUrl("http://localhost:8080")
.filter((request, next) ->
next.exchange(request)
.doOnNext(clientResponse -> {
if (clientResponse.statusCode() == HttpStatus.UNAUTHORIZED) {
throw new RuntimeException();
}
}).retryWhen(Retry.anyOf(RuntimeException.class)
.doOnRetry(objectRetryContext -> tokenProvider.expire())
.retryOnce())
).build();
}
EDIT one of the features with repeat/retry is that, it doesn't change the original request, in my case I needed to retrieve a new OAuth token, but the above sent the same (expired) token.
I did figure a way to do this using exchange filter, once OAuth password-flow is in spring-security-2.0 I should be able to have this integrated with AccessTokens etc, but in the mean time
ExchangeFilterFunction retryOn401Function(TokenProvider tokenProvider) {
return (request, next) -> next.exchange(request)
.flatMap((Function<ClientResponse, Mono<ClientResponse>>) clientResponse -> {
if (clientResponse.statusCode().value() == 401) {
ClientRequest retryRequest = ClientRequest.from(request).header("Authorization", "Bearer " + tokenProvider.getNewToken().toString()).build();
return next.exchange(retryRequest);
} else {
return Mono.just(clientResponse);
}
});
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…