为什么 RestController 中的 Flux.fromIterable() return 作为一个连接字符串返回?
Why is Flux.fromIterable() return in RestController coming back as one concatenated string?
我有一个 returns 一个 Flux<String>
的 Rest Conotroller,但是当我尝试将其收集到列表中时,它是所有串联字符串中的一个。我怎样才能得到它作为一个实际列表?
控制器:
@RestController
public class TestRestController
{
@GetMapping( "/getflux" )
public Flux<String> getFlux()
{
return Flux.fromIterable(
Arrays.asList(
"String 1",
"String 2"
)
);
}
}
调用控制器:
//This returns as a list of one item: "String 1String 2
List<String> response = WebClient.builder()
.baseUrl( "http://localhost:" + port + "/" )
.build()
.get()
.uri( "/getflux" )
.retrieve()
.bodyToFlux( String.class )
.collectList()
.block();
如何获取实际列表?
似乎是 List<String>
反序列化的问题(f.e、List<Integer>
和许多其他类型都运行良好)。我试图调整 Jackson 的 ObjectMapper 配置但失败了。也许您也应该自己尝试一下,甚至将问题提交给 Jackson Github 回购协议。
作为解决方法,您可以 return Mono<List<String>>
来自控制器方法:
@GetMapping("/getflux")
public Mono<List<String>> getFlux() {
return Flux.fromIterable(
Arrays.asList(
"String 1",
"String 2"
)
).collectList();
}
,并这样称呼它:
List<String> block = WebClient.builder()
.baseUrl("http://localhost:" + 8080 + "/")
.build()
.get()
.uri("/getflux")
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<String>>() {
})
.block();
结果是["String 1","String 2"]
。通过直接从 Web browser/curl/etc.
调用控制器方法,同样可以 returned
经过一些研究,这似乎是一个 Spring 错误,标记为 "working as intended"。
https://github.com/spring-projects/spring-framework/issues/20807
This is expected behavior. By default byte arrays, byte buffers, and String are treated as low level content (serialized output) and is rendered as is. In fact the Flux is streamed with each string written and flushed immediately.
The Jackson encoder explicitly backs out for element type String. I realize that String and an array of String's can be rendered as JSON but there are two ways to treat String content and this is what we've chosen by default.
唯一的解决办法是永远不要 return 一个 Flux<String>
而是 return 你制作的一些包装器 class 的列表。这仍然允许使用 Flux
和背压,并且 Spring 可以正确处理这种复杂的对象。
以下完美运行:
@GetMapping("/getflux")
public Flux<List<StringWrapper>> getFlux() {
return Flux.fromIterable(
Arrays.asList(
new StringWrapper( "String 1" ),
new StringWrapper( "String 2" )
)
);
}
我有一个 returns 一个 Flux<String>
的 Rest Conotroller,但是当我尝试将其收集到列表中时,它是所有串联字符串中的一个。我怎样才能得到它作为一个实际列表?
控制器:
@RestController
public class TestRestController
{
@GetMapping( "/getflux" )
public Flux<String> getFlux()
{
return Flux.fromIterable(
Arrays.asList(
"String 1",
"String 2"
)
);
}
}
调用控制器:
//This returns as a list of one item: "String 1String 2
List<String> response = WebClient.builder()
.baseUrl( "http://localhost:" + port + "/" )
.build()
.get()
.uri( "/getflux" )
.retrieve()
.bodyToFlux( String.class )
.collectList()
.block();
如何获取实际列表?
似乎是 List<String>
反序列化的问题(f.e、List<Integer>
和许多其他类型都运行良好)。我试图调整 Jackson 的 ObjectMapper 配置但失败了。也许您也应该自己尝试一下,甚至将问题提交给 Jackson Github 回购协议。
作为解决方法,您可以 return Mono<List<String>>
来自控制器方法:
@GetMapping("/getflux")
public Mono<List<String>> getFlux() {
return Flux.fromIterable(
Arrays.asList(
"String 1",
"String 2"
)
).collectList();
}
,并这样称呼它:
List<String> block = WebClient.builder()
.baseUrl("http://localhost:" + 8080 + "/")
.build()
.get()
.uri("/getflux")
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<String>>() {
})
.block();
结果是["String 1","String 2"]
。通过直接从 Web browser/curl/etc.
经过一些研究,这似乎是一个 Spring 错误,标记为 "working as intended"。
https://github.com/spring-projects/spring-framework/issues/20807
This is expected behavior. By default byte arrays, byte buffers, and String are treated as low level content (serialized output) and is rendered as is. In fact the Flux is streamed with each string written and flushed immediately.
The Jackson encoder explicitly backs out for element type String. I realize that String and an array of String's can be rendered as JSON but there are two ways to treat String content and this is what we've chosen by default.
唯一的解决办法是永远不要 return 一个 Flux<String>
而是 return 你制作的一些包装器 class 的列表。这仍然允许使用 Flux
和背压,并且 Spring 可以正确处理这种复杂的对象。
以下完美运行:
@GetMapping("/getflux")
public Flux<List<StringWrapper>> getFlux() {
return Flux.fromIterable(
Arrays.asList(
new StringWrapper( "String 1" ),
new StringWrapper( "String 2" )
)
);
}