WebClient не читает ответ до тех пор, пока не завершится запись запроса. - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь реализовать потоковый прокси. Я столкнулся с проблемой с WebClient от Spring реактивной.

Может ли кто-нибудь помочь мне понять, правильно ли я поступил, или это просто ошибка со стороны WebClient?

Stack:

реактор-нетто 0,7,8. РЕЛИЗ

пружинный ботинок 2.0.4. РЕЛИЗ

Описание изделия:

Я хочу передать длинный поток во внешнюю службу, а затем направить поток ответов запрашивающей стороне. Потоковая передача происходит с использованием чанков (HTTP 1.1 Transfer-Encoding: chunked). Внешний сервис обрабатывает каждый кусок и отправляет результат ответа.

Ожидаемое поведение:

WebClient должен немедленно прочитать каждую полученную часть ответа.

Фактическое поведение:

WebClient не запускает ответ процесса, пока не завершится запись запроса.

Код:

return client
    .post()
    .header("Transfer-Encoding", "chunked")
//because I want to flush each received part
    .body((outputMessage, context) -> outputMessage.writeAndFlushWith(
        request.body(BodyExtractors.toDataBuffers())
               .map(dataBuffer -> Mono.just(dataBuffer))))
    .exchange()
    .flatMap(clientResponse -> {
      ServerResponse.BodyBuilder bodyBuilder = ServerResponse.status(clientResponse.statusCode());
      bodyBuilder.contentType(MediaType.APPLICATION_STREAM_JSON);

      return bodyBuilder.body((outputMessage, context) ->                                                        
          outputMessage.writeAndFlushWith(                                               
            clientResponse.body(BodyExtractors.toDataBuffers())                                                               
                          .map(dataBuffer -> Mono.just(dataBuffer))
                         ));}
);

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

Только что протестировал реализацию WebClient на базе Jetty, и она работает так, как вы ожидаете. Он может начать чтение ответа до того, как все содержимое запроса будет отправлено. Это должно было быть выпущено в Spring Framework 5.1 Новая функция WebClient на Jetty

0 голосов
/ 01 сентября 2018

Я посмотрел его, и кажется, что в принципе, и Spring WebFlux WebClient, и Reactor Netty HttpClient предназначены для первой обработки запроса (отправки тела запроса), а затем чтения тела ответа.

Другие HTTP-клиенты могут разрешить это, но я думаю, что в этом случае это способ связать противодавление как в операциях чтения / записи, так и объединить все в один реактивный конвейер.

Возможно, вы ищете двунаправленный транспортный протокол, ориентированный на сообщения, с поддержкой противодавления. Вы можете взглянуть на WebSockets (хотя вам нужно будет определить собственную семантику сообщений там) или следить за RSocket .

Если вы просто ищете эффективный реактивный шлюз, то Spring Cloud Gateway - ваш лучший выбор, так как он полностью активен и поддерживает интересные дополнительные функции.

Несколько дополнительных примечаний:

Spring WebFlux (как на уровне клиента, так и на уровне сервера) использует реализации Encoder и Decoder, адаптируясь к сообщению Content-Type. Некоторые конкретные типы контента, такие как application/streaming+json или text/event-stream, реализованы с учетом сценариев потоковой передачи. Это означает, что кодеры пишут сообщения по мере их поступления, разделенные определенными символами, и сбрасываются в сети. Использование обычных типов носителей, таких как application/octet-stream или application/json, не приведет к такому поведению. В этих случаях прокси и посредники могут буферизировать тело сообщения и предоставлять большие / меньшие окна. Вот почему такие механизмы требуют разделителя между сообщениями и надлежащими кодеками.

Насколько я понимаю, вы используете HTTP 1.1, который использует механизм запроса / ответа - спецификация HTTP явно не запрещает серверу писать ответ до прочтения полного запроса, но говорит, что он должен прочитать полное тело запроса (или закрыть соединение), несмотря ни на что. См https://tools.ietf.org/html/rfc7230#section-3.4

Как всегда, вы можете запросить улучшения для https://jira.spring.io,, хотя в этом случае, я думаю, это сделано намеренно.

...