Добавление повторных запросов на все запросы WebClient - PullRequest
0 голосов
/ 08 июня 2018

у нас есть сервер для получения токена OAUTH, и токен oauth добавляется к каждому запросу с помощью метода WebClient.filter, например,

webClient
                .mutate()
                .filter((request, next) -> tokenProvider.getBearerToken()
                        .map(token -> ClientRequest.from(request)
                                .headers(httpHeaders -> httpHeaders.set("Bearer", token))
                                .build()).flatMap(next::exchange))
                .build();
TokenProvider.getBearerToken returns Mono<String> since it is a webclient request (this is cached)

Я хочу иметь функцию повтора, которая при ошибке 401 будетсделать токен недействительным и повторить запрос. У меня это работает вот так

webClient.post()
            .uri(properties.getServiceRequestUrl())
            .contentType(MediaType.APPLICATION_JSON)
            .body(fromObject(createRequest))
            .retrieve()
            .bodyToMono(MyResponseObject.class)
            .retryWhen(retryOnceOn401(provider))

private Retry<Object> retryOnceOn401(TokenProvider tokenProvider) {
        return Retry.onlyIf(context -> context.exception() instanceof WebClientResponseException && ((WebClientResponseException) context.exception()).getStatusCode() == HttpStatus.UNAUTHORIZED)
                .doOnRetry(objectRetryContext -> tokenProvider.invalidate());
    }

Есть ли способ перенести это в функцию webClient.mutate () ..... build ()?так что все запросы будут иметь эту возможность повторения?

Я пытался добавить в качестве фильтра, но, похоже, он не работал, например

.filter(((request, next) -> next.exchange(request).retryWhen(retryOnceOn401(tokenProvider))))

какие-либо предложения о наилучшем способе подойти к этому?Привет

1 Ответ

0 голосов
/ 08 июня 2018

Я понял это, что стало очевидно после того, как повторная попытка работает только для исключений, webClient не выдает исключение, поскольку объект clientResponse просто содержит ответ, только когда вызывается bodyTo, исключение выдается в статусе http, поэтомучтобы исправить это, можно имитировать это поведение

@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();
    }

РЕДАКТИРОВАТЬ Одной из функций с повтором / повтором является то, что она не меняет исходный запрос, в моем случае мне нужно было получитьновый OAuth-токен, но вышеуказанный отправил тот же (просроченный) токен.Я придумал способ сделать это с помощью фильтра Exchange, когда поток паролей OAuth будет в spring-security-2.0, я смогу интегрировать его с AccessTokens и т. Д., Но в то же время

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);
                    }
                });
    }
...