Я подхожу к конструкции реактора Spring и создаю «Api Composer», который вызывает различные микросервисы через Webflux.
По сути, мне нужно вызвать службу Учетная запись с произвольным apiToken и, если получен HTTP 401 - Unauthorized , он будет преобразован в пользовательское исключение, которое вызовет вызов microservice Token для его обновления и вызова службы Account с обновленным токеном.
Я нашел это решение, которое работает, но я не уверен, что это правильный способ выполнить эту задачу.
Класс маршрутизатора
@Configuration
public class MyRouter {
@Bean
public RouterFunction<ServerResponse> route(MyHandler handler) {
return RouterFunctions.route(POST("/lineAuthentication").and(accept(APPLICATION_XML)).and(contentType(APPLICATION_XML)), handler::lineAuthentication)
.andRoute(POST("/anotherMethod").and(accept(APPLICATION_XML)).and(contentType(APPLICATION_XML)), handler::checkPin);
}
}
Обслуживание учетной записи
public Mono<LineAuthenticationResponse> lineAuthentication(String apiToken, String businessId, String ip, String channel, boolean forceOk) {
return webClient.post()
.uri(builder -> builder.path("account/lineAuthentication")
.queryParam("ip", ip)
.build())
.header("businessId", businessId)
.retrieve()
.onStatus(status -> status == HttpStatus.UNAUTHORIZED, response -> Mono.error(new ExpiredTokenException(response.statusCode(), "token Expired")))
.bodyToMono(LineAuthenticationResponse.class);
}
Служба токенов
public Mono<TokenAdapterResponse> getToken(String businessId) {
Mono<TokenAdapterResponse> tokenMono = webClient.get()
.uri("token/getToken")
.retrieve()
.bodyToMono(TokenAdapterResponse.class);
return tokenMono;
}
MyHandler
public Mono<ServerResponse> lineAuthentication(ServerRequest serverRequest) {
.....
Mono<LineAuthentication> lineDataRequest = serverRequest.bodyToMono(LineAuthentication.class);
generatedBusinessId = generateBusinessId();
Mono<ServerResponse> lineAuthenticationResponse = lineDataRequest.flatMap(lineData -> ok().contentType(APPLICATION_XML)
.body(fromPublisher(
handleLineAuthRequest(apiToken, generatedBusinessId, lineData.getServiceData().getIp(), lineData.getServiceData().getChannel(), false).onErrorResume(
ExpiredTokenException.class,
e -> handleTokenExpiredException(generatedBusinessId, lineData.getServiceData().getIp(), lineData.getServiceData().getChannel())),
LineAuthenticationResponse.class)))
.switchIfEmpty(notFound().build());
return lineAuthenticationResponse;
}
private Mono<LineAuthenticationResponse> handleLineAuthRequest(String apiKey, String businessId, String ip, String channel, boolean forceOk) {
System.out.println("handling Line Authentication request");
return accountService.lineAuthentication(apiToken, businessId, ip, channel, forceOk);
}
private Mono<LineAuthenticationResponse> handleTokenExpiredException(String generatedBusinessId, String ip, String channel) {
System.out.println("Expired token exception caugth");
Mono<TokenAdapterResponse> tokenMono = tokenService.getToken(generatedBusinessId).doOnNext(newToken -> updateApiToken(newToken.getResponse().getAccess_token()));
Mono<LineAuthenticationResponse> map = tokenMono
.zipWhen(tokenResp -> handleLineAuthRequest(tokenResp.getResponse().getAccess_token(), generatedBusinessId, ip, channel, true)).map(tuple -> {
tuple.getT1();
tuple.getT2();
return tuple.getT2();
});
return map;
}
В конце концов, если последовательность вызываемых микросервисов велика, что может быть лучшим способом их последовательного вызова?
A -> B -> C (B не может быть вызван до A, и C не может быть вызван до B).