代码之家  ›  专栏  ›  技术社区  ›  posthumecaver

将几个REST调用与Spring Webflux相结合

  •  8
  • posthumecaver  · 技术社区  · 8 年前

    我试图用SpringWebFlux做点什么,但我真的对一些被动的概念感到困惑。

    我有一些受表单身份验证保护的REST服务,在调用我的业务REST服务之前,我必须调用通过Spring Security提供的“登录”URL,传递我的凭据,并将返回的Cookie放置到其他REST服务的进一步调用中。

    下面是对REST业务服务的调用片段。。。。

    @RequestMapping(value = "/endpoint1", method = RequestMethod.POST)
    public Mono<String> businessService(@RequestBody ApiManagementWrapper apiManagementWrapper, ServerWebExchange httpRequest) {
        log.info("Handling /enpoint1");
    
        Mono<String> t = fetch(apiManagementWrapper, httpRequest);
    
        return t;
    }
    
    private Mono<String> fetch(ApiManagementWrapper apiManagementWrapper, ServerWebExchange httpRequest) {
        return this.webClientProxy
                .post()
                .uri("http://localhost:8081/something")
                .headers(httpHeaders ->  httpRequest.getRequest().getHeaders())
                .cookies(httpCookies -> httpRequest.getRequest().getCookies())
                .body(BodyInserters.fromPublisher(Mono.just(apiManagementWrapper.getEnterpriseMessage()), Object.class))
                .exchange()
                .flatMap(response -> response.bodyToMono(String.class));
    }
    

    我的问题是如何将其与呼叫登录服务结合起来。。

    我考虑了以下login()方法。。。

    private void login(ApiManagementWrapper apiManagementWrapper) {
        LinkedMultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("username", "user1");
        formData.add("password", "user1");
    
        Mono<ClientResponse> response =  this.webClientRouteConfirmation
                .post()
                .uri("http://localhost:8383/login")
                .body(BodyInserters.fromFormData(formData))
                .exchange();
    
        response.subscribe(clientResponse -> {
            handleLogin(clientResponse.cookies().getFirst("JSESSION_ID"), apiManagementWrapper);
        });
    }
    
    private void handleLogin(ResponseCookie loginCookie, ApiManagementWrapper apiManagementWrapper){
        Mono<Route> route = loadRoute(apiManagementWrapper.getEnterptiseContext(), loginCookie);
        if(route == null) {
            return;
        }
    }
    
    
    private Mono<Route> loadRoute(EnterpriseContext enterpriseContext, ResponseCookie loginCookie) {
        Mono<Route> route = this.webClientRouteConfirmation
                .get()
                .uri("http://localhost:8383/routes/search/findByServiceIdAndClientId?serviceName=" + enterpriseContext.getTarget() + "&clientName" + enterpriseContext.getSource())
                .cookie("JSESSION_ID", loginCookie.getValue())
                .exchange()
                .flatMap(clientResponse -> clientResponse.bodyToMono(Route.class));
    
        route.subscribe(r -> {
           handleRoute(enterpriseContext, loginCookie);
        });
    }
    

    使用“login()”方法,我可以获得“JSESSION\u ID”Cookie,但虽然它返回Mono,但我无法访问Cookie值(我可以使用clientResponse.block(),但我知道这是邪恶的,所以尽量不要这样做),所以我尝试使用回调订阅clientResponse,但如果我尝试这样做,我将与“businessService()”方法分离,并且无法返回我喜欢的值。。。

    因此,我想作为伪代码实现的是。。。。

    @RequestMapping(value = "/endpoint1", method = RequestMethod.POST)
    public Mono<String> businessService(@RequestBody ApiManagementWrapper apiManagementWrapper, ServerWebExchange httpRequest) {
        log.info("Handling /netty1");
    
        Route route = login(apiManagementWrapper);
    
        Mono<String> t = null;
        if(route != null) {
            t = fetch(apiManagementWrapper, httpRequest);
        }
    
        return t;
    }
    

    但我不知道如果不使用单声道,如何去那里。块()。。

    从“handleLogin()”返回“Route”对象没有任何意义,因为如果我正确理解了反应式概念,“fetch()”方法无论如何都不会等待它。。。。

    有什么建议吗?

    1 回复  |  直到 8 年前
        1
  •  7
  •   Brian Clozel    8 年前

    您可以在全球范围内应用的内容:

    • 使您的方法返回被动类型,如 Mono<T> Flux<T>
    • 避免使用 subscribe 在web应用程序中,因为它将执行与当前请求/响应分离,并且不能保证完成该任务

    然后可以使用可用的操作符组合这些反应类型。类似于:

    Mono<LoginInformation> login = doLogin();
    Mono<String> value = login.flatMap(info -> callRemoteService(info));