我试图用Spring Webflux做一些事情,但我真的对一些反应性概念感到困惑 .
我有一些使用表单身份验证保护的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_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;
}
但我不知道如何在不使用Mono.block()的情况下去那里 .
从'handleLogin()'返回'Route'对象没有任何意义,因为如果我正确理解Reactive概念,'fetch()'方法无论如何都不会等待它....
有小费吗?
1 回答
您可以全局申请的东西:
让你的方法返回反应类型,如
Mono<T>
或Flux<T>
避免在Web应用程序中使用
subscribe
,因为它将执行与当前请求/响应分离,并且不保证该任务的完成然后,您可以使用可用的运算符组成这些反应类型 . 就像是: