復帰時スプリングWebfluxとWebクライアントで遊んでいる間、私は(以下のコードによって実証)挙動を注目ServerResponse含有しますFlux<String>
。ない限り、文字列の要素を返し、改行文字で終了しているFlux<String>
経由ServerResponseすべて連結するように見えるFlux<String>
単一の中に要素を文字列。誰かが私はこの振る舞いを見ている、と私はそれを引き起こすためにやっている理由を私に説明できますか?
各ときに文字列の要素が改行文字で終端され、Flux<String>
経由して「予想通りに返される」ServerResponse、と返さに加入Flux<String>
期待される結果を生成します。(ポストマンを介して)単純なJSONとみなす場合は、これはまた、余分になる、空、文字列要素は、JSON本体に戻されます。
説明挙動を示すコンソール出力...
- 最初のリストの文字列要素がで起こる)(StringProducerHandler.getAll、との結果を示して
Flux<String>
含有する10 列の各々の第2の発生要素、文字列値が空白行である出力が得られ、改行文字で終端されます。 第二のリストの文字列要素がで起こる)(StringClient.getAll、およびオリジナルの方法を示して文字列の改行文字で終了していなかった要素は、以下の要素と連結されています。
2019年10月10日10:13:37.225 INFO 8748 --- [メイン] osbweb.embedded.netty.NettyWebServer:網状は、(複数の)ポートで開始:8080 2019年10月10日10:13:37.228 INFO 8748 --- [メイン] c.example.fluxtest.FluxTestApplication:1.271秒(JVMが1.796のために実行されている)で開始FluxTestApplication
/ localhostを:8080 / StringClient /文字列StringClientHandler.getAll(ServerRequest)StringClient.getAll()StringProducerHandler.getAll(ServerRequest)ListElement-0 ListElement-0 *****のhttpに発行された "GET"
listelement listelement-1-1
listelement-2-2 listelement
listelement-3-3 listelement
listelement listelement-4-4
listelement-0listelement-listelement-1listelement-1 @ 0 @ 1570727628948 1570727628948 1570727628948 listelement listelement-2listelement-2-3listelement-3 @ @ @ 1570727628949 1570727628948 listelement-4-4listelement
この動作を再現するコードを以下にされています...
@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);
}
}
これはどのように起因しているorg.springframework.core.codec.StringDecoder
作品。
あなたが呼び出すとresponse.bodyToFlux(String.class)
、応答本体はに変換されるFlux
のString
秒。org.springframework.core.codec.StringDecoder
重い物を持ち上げるを行い、それがデフォルトの区切り文字で分割すべきであるという意見を持っています。
List<byte[]> delimiterBytes = getDelimiterBytes(mimeType);
Flux<DataBuffer> inputFlux = Flux.from(input)
.flatMapIterable(buffer -> splitOnDelimiter(buffer, delimiterBytes))
.bufferUntil(buffer -> buffer == END_FRAME)
.map(StringDecoder::joinUntilEndFrame)
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
return super.decode(inputFlux, elementType, mimeType, hints);
デフォルトの区切り文字は、 public static final List<String> DEFAULT_DELIMITERS = Arrays.asList("\r\n", "\n");
したがって、あなたが得ます:
ListElement-0ListElement-0 @ 1570732000374
ListElement-1ListElement-1 @ 1570732000375
...
の代わりに
ListElement-0 @ 1570732055461
ListElement-0 @ 1570732055461
ListElement-1 @ 1570732055462
ListElement-1 @ 1570732055462
...