#java #spring #spring-boot #spring-webflux #spring-webclient
Вопрос:
Я пытаюсь построить логику повторных попыток с помощью 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
Ответ №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
экземпляр вместо создания нового для каждого запроса.
Комментарии:
1. Спасибо. Мне кажется, я вижу свою проблему. Я работаю над тем, чтобы завершить его в эти выходные, и предоставляю вам свои отзывы.
2. Спасибо. Ваш ответ помог мне двигаться в правильном направлении.
Do not block when renewing token
У меня было много работы. Видишь github.com/reflexdemon/home-use/pull/1 чтобы увидеть изменения, необходимые для преобразования простого загрузочного приложения в реактивное приложение.