【问题标题】:Spring WebClient Retry Logic with new Headers带有新标头的 Spring WebClient 重试逻辑
【发布时间】:2021-10-07 06:41:42
【问题描述】:

我正在尝试使用 Spring WebClient 构建重试逻辑。我要解决的问题非常简单。我正在调用 API 端点来获取一些值。如果 API 返回错误并显示 401 响应,那么我将不得不调用令牌服务并更新我的令牌并使用新令牌并进行相同的 API 调用。

一般的psudo是

try {
    GET /locations data
} catch(401 Unauthorized) {
    POST /token and get renew Token --> This is another WebClient API call With New Token
    call again GET /locations and return value
} catch (Another Exception) {
    throw Application Error
}

这是我正在尝试执行的 Spring 代码,但它看起来并不工作。 关于如何做的任何建议。

public List<Location> getLocations(final User user) {
    if (null == user) {
        throw new ApplicationException("User cannot be null");
    }

    if (null == user.getHoneyWellLinkToken()) {
        throw new ApplicationException(String.format("%s has not linked the account with Honeywell", user.getUsername()));
    }


    List<Location> locations = getLocationsAPI(user).block();

    return locations;

}

private Mono<List<Location>> getLocationsAPI(final User user) {
    String endpoint = config.getApi().getLocationsEndpoint()
                .concat("?apikey=")
                .concat(config.getCredentials().getClientId());

    return WebClient.builder().baseUrl(endpoint)
                .build()
                .get()
                .headers(httpHeaders -> httpHeaders.setBearerAuth(user.getHoneyWellLinkToken().getAccessToken()))
                .retrieve()
                .bodyToFlux(Location.class)
                .collectList()
                .doOnError(err -> {
                    WebClient.builder().baseUrl(endpoint)
                            .build()
                            .get()
                            .headers(httpHeaders -> httpHeaders.setBearerAuth(honeywellService.renewToken(user).block().getHoneyWellLinkToken().getAccessToken()))
                            .retrieve().bodyToFlux(Location.class);

                });

}

此代码托管在 GitHub https://github.com/reflexdemon/home-use/blob/main/src/main/java/io/vpv/homeuse/service/HoneywellThermostatService.java

【问题讨论】:

    标签: java spring spring-boot spring-webflux spring-webclient


    【解决方案1】:
    • 使用onErrorResume 而不是doOnError
    • 更新令牌时不要block
        private Mono<List<Location>> getLocationsAPI(final User user) {
            String endpoint = config.getApi().getLocationsEndpoint()
                                    .concat("?apikey=")
                                    .concat(config.getCredentials().getClientId());
    
            return getLocations(endpoint, user)
                .onErrorResume(err -> honeywellService.renewToken(user)
                                                      .flatMap(newUser -> getLocations(endpoint, newUser)));
    
        }
    
        private Mono<List<Location>> getLocations(String endpoint, User user) {
            return WebClient.builder()
                            .baseUrl(endpoint)
                            .build()
                            .get()
                            .headers(httpHeaders -> httpHeaders.setBearerAuth(user
                                .getHoneyWellLinkToken()
                                .getAccessToken()))
                            .retrieve()
                            .bodyToFlux(Location.class)
                            .collectList();
        }
    

    此外,最好使用单个 WebClient 实例,而不是为每个请求构建一个新实例。

    【讨论】:

    • 谢谢。我想我看到了我的问题。我正在努力在这个周末完成它并向您提供我的反馈。
    • 谢谢。您的回答帮助我朝着正确的方向前进。 Do not block when renewing token 做了很多工作。请参阅github.com/reflexdemon/home-use/pull/1,了解将简单的启动应用程序转换为反应式应用程序所需的更改。
    猜你喜欢
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2019-04-25
    • 2020-12-25
    相关资源
    最近更新 更多