Spring Reactor:这是顺序调用远程api的正确方法吗?

时间:2019-03-21 00:51:09

标签: spring spring-webflux reactor

我正在接近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)。

0 个答案:

没有答案