Потоковая передача пользовательских типов мультимедиа с помощью WebClient - PullRequest
0 голосов
/ 28 апреля 2020

Spring Webflux обеспечивает потоковую поддержку конечной точки контроллера из коробки, если вы запрашиваете конечную точку, возвращающую Flux<Foo> с Accept: application/stream+json или Accept: text/event-stream.

Теперь я хотел бы представить другое представление Foo OtherFoo, который должен быть возвращен из нашей /foos конечной точки через Accept: application/prs.other-foo-stream+json (например).

Теперь я попытался протестировать всю установку, используя следующий код

data class Foo(
        val id: UUID = UUID.randomUUID()
)

@RestController
@RequestMapping("/test")
class TestController(
        webClientBuilder: WebClient.Builder
) {

    private val client = webClientBuilder
            .baseUrl("http://localhost:8080/test")
            .build()

    private fun data() = Flux.range(0, 3)
            .map { Foo() }
            .delayElements(Duration.ofSeconds(1))

    @GetMapping
    fun findAll() = data()

    @GetMapping(produces = ["application/x.foo+json"])
    fun findAllAsFoo() = data()

    @GetMapping(produces = ["application/x.foo-stream+json"])
    fun findAllAsFooSse(): Flux<ServerSentEvent<Foo>> = data()
            .map {
                ServerSentEvent.builder<Foo>()
                    .data(it)
                    .build()
            }

    @PostMapping
    fun test(@RequestParam accept: String) = client
            .get()
            .accept(MediaType.parseMediaType(accept))
            .retrieve()
            .bodyToFlux<Foo>()

}

Отображения запроса выглядят нормально, и если вы запрашиваете пользовательскую конечную точку GET напрямую, ответ возвращается через SSE

➜ http --stream :8080/test "Accept: application/x.foo-stream+json"
HTTP/1.1 200 OK
Content-Type: text/event-stream;charset=UTF-8
transfer-encoding: chunked

data:{"id":"54d6570d-9ee4-4792-adce-1be035f20bc3"}

data:{"id":"87f50fbc-2780-4730-a11c-2165e975614b"}

data:{"id":"557cacca-9e3d-4322-b7ef-b2201301a636"}

Если я запрашиваю конечную точку с помощью "WebClient redirect" через

➜ http -v --stream POST :8080/test accept=="application/x.foo-sse+json" "Accept: application/stream+json"
POST /test?accept=application%2Fx.foo-sse%2Bjson HTTP/1.1
Accept: application/stream+json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
Host: localhost:8080
User-Agent: HTTPie/2.1.0



HTTP/1.1 200 OK
Content-Type: application/stream+json
transfer-encoding: chunked

{
    "id": "d1bc7075-eef7-460a-ad72-1440a432fcb5"
}
{
    "id": "6e1a4384-cb5b-445d-9fd9-d05f53fda5f8"
}
{
    "id": "b7c31c5f-1344-4afc-a4b1-5688fa5fc1c3"
}

ответ также передается в потоковом режиме, но я получаю все сообщения одновременно (обратите внимание на 1-секундную задержку в data()), что говорит о том, что WebClient на самом деле не передает поток, если он не запрашивает сам поток, используя .accept().

Настраиваемая конечная точка отвечает Content-Type: text/event-stream;charset=UTF-8, хотя WebClient должно быть хорошо, принимая ответ в виде потока.

Есть ли способ обслуживания (I thi Эта часть решена путем возврата Flux<ServerSentEvent<*>>) и извлечения потоков с пользовательскими типами мультимедиа с помощью Webflux / WebClient?

...