我正在接近Spring反应器框架,正在构建一个通过Webflux调用各种微服务的“ Api Composer”。
本质上,我需要使用任意apiToken调用服务帐户,如果收到 HTTP 401-未经授权,它将被映射到一个自定义异常中,该异常将触发调用微服务令牌进行更新,并使用刷新后的令牌重新调用帐户服务。
我发现此解决方案有效,但是我不确定这是否是完成此任务的正确方法。
路由器类
@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(不能在A之前调用B,并且不能在B之前调用C)。