我正在尝试在REST服务器和调用客户端应用程序之间编写一种代理,以便通过向REST调用添加属性来强制实现隐私。
我不想检查来自服务器的响应,我只想将其传递给客户端。
我想用spring-webflux做这个,因为我希望用事件驱动的方法来节省一些CPU。但我完全陷入困境。
这是我尝试的内容:
public Mono<ServerResponse> select(ServerRequest request) {
return request.principal().flatMap((principal) -> {
return WebClient.create(solrUrl).get().uri(f -> {
URI u = f.path(request.pathVariable("a")).path("/b/").queryParams(queryModifier.modify(principal, request.pathVariable("collection"), request.queryParams()).block()).build();
if (debug) {
log.debug("Calling {}", u);
}
return u;
})
.exchange()
.flatMap((ClientResponse mapper) -> {
BodyBuilder bodyBuilder = ServerResponse.status(mapper.statusCode());
bodyBuilder.body(BodyInserters.fromDataBuffers(mapper.bodyToFlux(DataBuffer.class)));
bodyBuilder.headers(c -> mapper.headers().asHttpHeaders().forEach((name, value) -> c.put(name, value)));
//.body(DefaultserverreBodyInserters.fromPublisher(mapper.bodyToMono(DataBuffer.class), DataBuffer.class)));
//.body(BodyInserters.fromDataBuffers(mapper.bodyToFlux(DataBuffer.class))));
//.body(BodyInserters.fromDataBuffers(mapper.body(BodyExtractors.toDataBuffers()))));
//.body(mapper.bodyToMono(String.class), String.class));
//.build());
return bodyBuilder.build();
});
});
}
我通过RouterFunction将其绑定到面向REST API的客户端:
@Configuration
public class VoiceRouterFunctions {
@Bean
public RouterFunction<ServerResponse> route(ClientPropertiesRequestHandler handler) {
return RouterFunctions.route(RequestPredicates.GET("/v3/{a}/select")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::select);
}
}
响应是200 - 好,身体里什么都没有。有什么想法吗?
答案 0 :(得分:2)
以下是您的问题的解释,我希望它可以帮助您理解为什么会发生这种情况。
您的问题中的错误如下:BodyBuilder.body(...)
方法实际构建,返回 a Mono<ServerResponse>
,但它确实不修改构建器。如果您查看source code of the builder,可以看到这一点。
通过查看代码更容易理解:
BodyBuilder bodyBuilder = ServerResponse.status(...); // 1
bodyBuilder.body(...); // 2
bodyBuilder.headers(...); // 3
return bodyBuilder.build(); // 4
这就是发生的事情:在第1行你创建了一个构建器,在第2行你添加了一个体并构建它,但你没有将结果存储在一个变量中(oops!),然后在第3行你添加了头到初始构建器,它没有正文,因为body(...)
函数不修改构建器,而在第4行构建并返回空构建器。所以,在你的情况下,第2行什么都不做。
正如您在答案中偶然发现的那样,解决方案是在最后调用body(...)
函数,它应该是最后一个!
以下示例也有效。注意线的新顺序。
BodyBuilder bodyBuilder = ServerResponse.status(...); // 1
bodyBuilder.headers(...); // 3
return bodyBuilder.body(...); // 2
答案 1 :(得分:1)
由于某种原因,我无法理解,这有效:
public Mono<ServerResponse> select(ServerRequest request) {
return request.principal().flatMap((principal) -> {
return client.get().uri(f -> {
URI u = f.path(request.pathVariable("collection")).path("/select/").queryParams(queryModifier.modify(principal, request.pathVariable("collection"), request.queryParams()).block()).build();
if (debug) {
log.debug("Calling {}", u);
}
return u;
})
.exchange()
.flatMap((ClientResponse mapper) -> {
return ServerResponse.status(mapper.statusCode())
.headers(c -> mapper.headers().asHttpHeaders().forEach((name, value) -> c.put(name, value)))
.body(mapper.bodyToFlux(DataBuffer.class), DataBuffer.class);
});
});
}
我已经尝试了十几种或更多种变体,之前没有任何效果,但现在这个......任何人都可以解释,为什么,以及为什么它必须具体呢?对不起,但是一个不会调试的API,我不得不回到试用版和错误让我感到紧张......
答案 2 :(得分:0)
我编写了以下方法将ClientResponse
转换为ServerResponse
:
private static Mono<ServerResponse> fromClientResponse(ClientResponse clientResponse){
return ServerResponse.status(clientResponse.statusCode())
.headers(headerConsumer -> clientResponse.headers().asHttpHeaders().forEach(headerConsumer::addAll))
.body(clientResponse.bodyToMono(String.class), String.class);
}