Играя с Spring Webflux и WebClient, я заметил поведение (демонстрируемое приведенным ниже кодом) при возврате ServerResponse , содержащего Flux<String>
. Если элементы String не заканчиваются символом новой строки, возвращение Flux<String>
через ServerResponse , по-видимому, объединяет все Flux<String>
элементы в один String . Может кто-нибудь объяснить мне, почему я вижу это поведение и что я делаю, чтобы вызвать его?
Когда каждый элемент String заканчивается символом новой строки, Flux<String>
возвращается «как ожидалось» через ServerResponse , и подписка на возвращенное Flux<String>
дает ожидаемые результаты. Однако, если рассматривать его как простой JSON (через Postman), это также приводит к тому, что в тело JSON возвращается дополнительный пустой элемент String.
Вывод на консоль, показывающий описанное поведение ...
- Первый список String элементов содержится в StringProducerHandler.getAll () и указывает на результаты
Flux<String>
, содержащие 10 String элементов, где второе вхождение каждого значения String заканчивается символом новой строки, в результате чего выводится пустая строка. Второй список Элементы String находятся в StringClient.getAll () и демонстрируют, как исходные элементы String , которые не заканчивались символом новой строки, были объединены со следующим элементом.
2019-10-10 10: 13: 37.225 INFO 8748 --- [main] osbweb.embedded.netty.NettyWebServer: Netty запущен на портах: 8080 2019-10-10 10: 13: 37.228 INFO8748 --- [основной] в. example.fluxtest.FluxTestApplication: Запущено приложение FluxTestApplication за 1,271 секунды (JVM работает в течение 1,796)
***** «Get» выдано для http: / localhost: 8080 / StringClient / String StringClientHandler.getAll (ServerRequest) StringClient.getAll () StringProducerHandler.getAll (ServerRequest) ListElement-0 ListElement-0
ListElement-1 ListElement-1
ListElement-2 ListElement-2
ListElement-3 ListElement-3
ListElement-4 ListElement-4
ListElement-0ListElement-0 @ 1570727628948 ListElement-1ListElement-1 @ 1570727628948 ListElement-2ListElement-2 @ 1570727670Lelement-3 @ 1570727632Element 3-го уровня4ListElement-4 @ 1570727628949
Код для воспроизведения этого поведения приведен ниже ...
@SpringBootApplication
public class FluxTestApplication {
public static void main(String[] args) {
SpringApplication.run(FluxTestApplication.class, args);
}
}
@Configuration
public class StringClientRouter {
@Bean
public RouterFunction<ServerResponse> clientRoutes(StringClientHandler requestHandler) {
return nest(path("/StringClient"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/String"), requestHandler::getAll)));
}
}
@Component
public class StringClientHandler {
@Autowired
StringClient stringClient;
public Mono<ServerResponse> getAll(ServerRequest request) {
System.out.println("StringClientHandler.getAll( ServerRequest )");
Mono<Void> signal = stringClient.getAll();
return ServerResponse.ok().build();
}
}
@Component
public class StringClient {
private final WebClient client;
public StringClient() {
client = WebClient.create();
}
public Mono<Void> getAll() {
System.out.println("StringClient.getAll()");
// break chain to explicitly obtain the ClientResponse
Mono<ClientResponse> monoCR = client.get().uri("http://localhost:8080/StringProducer/String")
.accept(MediaType.APPLICATION_JSON)
.exchange();
// extract the Flux<String> and print to console
Flux<String> fluxString = monoCR.flatMapMany(response -> response.bodyToFlux(String.class));
// this statement iterates over the Flux<String> and outputs each element
fluxString.subscribe(strVal -> System.out.println(strVal + " @ " + System.currentTimeMillis()));
return Mono.empty();
}
}
@Configuration
public class StringProducerRouter {
@Bean
public RouterFunction<ServerResponse> demoPOJORoute(StringProducerHandler requestHandler) {
return nest(path("/StringProducer"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/String"), requestHandler::getAll)));
}
}
@Component
public class StringProducerHandler {
public Mono<ServerResponse> getAll(ServerRequest request) {
System.out.println("StringProducerHandler.getAll( ServerRequest )");
int listSize = 5;
List<String> strList = new ArrayList<String>();
for (int i=0; i<listSize; i++) {
strList.add("ListElement-" + i); // add String value without newline termination
strList.add("ListElement-" + i + "\n"); // add String value with newline termination
}
// this statement produces the expected console output of String values
Flux.fromIterable(strList).subscribe(System.out::println);
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Flux.fromIterable(strList), String.class);
}
}