将 ClientResponse 转换为 ServerResponse
Convert ClientResponse to ServerResponse
我正在尝试在 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 - OK,正文中没有任何内容。有什么想法吗?
出于某种原因我无法理解,这有效:
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 不适合调试,我不得不退回到试错法,这让我很紧张...
以下是对你的问题的解释,希望能帮助你理解为什么会出现这种情况。
您问题中的错误如下:BodyBuilder.body(...)
方法实际上 builds 和 returns Mono<ServerResponse>
,但它 不会 修改生成器。如果您查看 source code of the builder.
就可以看到这一点
看你的代码更容易理解:
BodyBuilder bodyBuilder = ServerResponse.status(...); // 1
bodyBuilder.body(...); // 2
bodyBuilder.headers(...); // 3
return bodyBuilder.build(); // 4
事情是这样的:在第 1 行你创建了一个构建器,在第 2 行你添加了一个 body 并构建它,但你没有将结果存储在变量中(糟糕!),然后在第 3 行,您将 headers 添加到初始构建器,它没有 body,因为 body(...)
函数不会修改构建器,在第 4 行,您构建并 return 空的建造者。所以,在你的情况下,第 2 行什么都不做。
解决方案,正如你在回答中偶然发现的那样,是在最后调用body(...)
函数,它应该是最后一个!
下面的例子也可以。注意行的新顺序。
BodyBuilder bodyBuilder = ServerResponse.status(...); // 1
bodyBuilder.headers(...); // 3
return bodyBuilder.body(...); // 2
我编写了以下方法将 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);
}
纯转换,本意是每次不加载body到内存,如下所示:
Mono<ServerResponse> monoResponse =
webClient
.method(method)
.uri(uri)
.headers(headers)
.body(someBodyInserter)
// pass-through
.retrieve()
.onRawStatus(status -> true, response -> Mono.empty())
.toEntityFlux(DataBuffer.class)
.flatMap(response -> ServerResponse
.status(response.getStatusCode())
.headers(respHeaders -> filterResponseHeaders(response.getHeaders(), respHeaders))
.body(BodyInserters.fromDataBuffers(response.getBody())));
我正在尝试在 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 - OK,正文中没有任何内容。有什么想法吗?
出于某种原因我无法理解,这有效:
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 不适合调试,我不得不退回到试错法,这让我很紧张...
以下是对你的问题的解释,希望能帮助你理解为什么会出现这种情况。
您问题中的错误如下:BodyBuilder.body(...)
方法实际上 builds 和 returns Mono<ServerResponse>
,但它 不会 修改生成器。如果您查看 source code of the builder.
看你的代码更容易理解:
BodyBuilder bodyBuilder = ServerResponse.status(...); // 1
bodyBuilder.body(...); // 2
bodyBuilder.headers(...); // 3
return bodyBuilder.build(); // 4
事情是这样的:在第 1 行你创建了一个构建器,在第 2 行你添加了一个 body 并构建它,但你没有将结果存储在变量中(糟糕!),然后在第 3 行,您将 headers 添加到初始构建器,它没有 body,因为 body(...)
函数不会修改构建器,在第 4 行,您构建并 return 空的建造者。所以,在你的情况下,第 2 行什么都不做。
解决方案,正如你在回答中偶然发现的那样,是在最后调用body(...)
函数,它应该是最后一个!
下面的例子也可以。注意行的新顺序。
BodyBuilder bodyBuilder = ServerResponse.status(...); // 1
bodyBuilder.headers(...); // 3
return bodyBuilder.body(...); // 2
我编写了以下方法将 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);
}
纯转换,本意是每次不加载body到内存,如下所示:
Mono<ServerResponse> monoResponse =
webClient
.method(method)
.uri(uri)
.headers(headers)
.body(someBodyInserter)
// pass-through
.retrieve()
.onRawStatus(status -> true, response -> Mono.empty())
.toEntityFlux(DataBuffer.class)
.flatMap(response -> ServerResponse
.status(response.getStatusCode())
.headers(respHeaders -> filterResponseHeaders(response.getHeaders(), respHeaders))
.body(BodyInserters.fromDataBuffers(response.getBody())));