添加重试WebClient的所有请求

时间:2018-06-08 01:05:39

标签: spring-webflux project-reactor

我们有一台服务器来检索OAUTH令牌,并通过WebClient.filter方法将oauth令牌添加到每个请求中 e.g

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

我想要一个重试功能,在401错误时,将使令牌无效并再次尝试请求 我有这样的工作

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

有没有办法将它移到webClient.mutate()..... build()函数? 以便所有请求都有这个重试工具?

我尝试添加过滤器,但它似乎不起作用。

FROM python:3.5

有关最佳方法的任何建议吗? 此致

1 个答案:

答案 0 :(得分:5)

我想到了这一点,在看到重试只对异常有效后很明显,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令牌,但上面发送了相同(已过期)令牌。 我确实想办法使用交换过滤器,一旦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("Authorisation", "Bearer " + tokenProvider.getNewToken().toString()).build();
                        return next.exchange(retryRequest);
                    } else {
                        return Mono.just(clientResponse);
                    }
                });
    }