как использовать конечную точку webflux для создания json-потоков из React

Я хочу узнать, как использовать Restcontroller WebFlux, создающий потоки json из React. Моя первая попытка заставила меня разобрать текст вместо json, но у меня такое чувство, что я делаю что-то странное. Я решил потратить силы на чтение примеров и нашел пример, возвращающий org.reactivestreams.Publisher вместо возврата WebFlux.

Я нашел немного устаревшую тему, которая могла мне помочь (Невозможно использовать ответ Webflux Streaming в клиенте React-Native), но у него нет однозначного ответа. Это заставило меня где-то прочитать, что React может не соответствовать Reactive, но это был очень старый пост.

Взяв образец из Интернета, если вы посмотрите на https://developer.okta.com/blog/2018/09/25/spring-webflux-websockets-react в основном вы найдете:

WebFlux производит Json, НО НЕ ПОТОК:

RestController producing MediaType.APPLICATION_JSON_VALUE and returning org.reactivestreams.Publisher<the relevant pojo> 

Реагировать на использование json:

 async componentDidMount() {
    const response = await fetch('relevant url');
    const data = await response.json();
  }

Я пробовал аналогичный подход, но с двумя существенными различиями:

Я возвращаю MediaType.TEXT_EVENT_STREAM_VALUE, потому что считаю, что предпочитаю возвращаемые потоки, поскольку я работаю с кодом без блокировки и вместо того, чтобы возвращать org.reactivestreams.Publisher, я понимаю, что имеет смысл вернуть Webflux, чтобы правильно использовать преимущества Spring 5 +.

мой контроллер отдыха Webflux:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.mybank.web.model.Loans;
import com.mybank.web.service.LoansService;

import reactor.core.publisher.Flux;

@RestController
public class LoansController {
    @Autowired
    private LoansService loansService;

    @CrossOrigin
    @RequestMapping(method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ResponseBody
    public Flux<Loans> findAll() {
        Flux<Loans> loans = loansService.findAll();
        return loans;
    }
}

Результатом является явно поток, а не json (скопировано из Postman):

data:{"timestamp":1558126555269,"result":"8"}

data:{"timestamp":1558132444247,"result":"10"}

data:{"timestamp":1558132477916,"result":"10"}

data:{"timestamp":1558132596327,"result":"14"}

Стек основан на загрузке MongoDb и Spring, но я не собираюсь вставлять здесь, поскольку это не актуально.

Реагировать

  async componentDidMount() {
    const response = await fetch('http://localhost:8080');
    const data = await response.json();
  }

Я получаю сообщение «Непойманный (в обещании) SyntaxError: Неожиданный токен d в JSON в позиции 0» по очень очевидной причине: я не возвращаю действительный json.

Затем, если я изменю контроллер Webflux для создания json (производит = MediaType.APPLICATION_JSON_VALUE), остальной контроллер не ответит мне ни потоком, ни результатом из кода без блокировки.

[
    {
        "timestamp": 1558126555269,
        "result": "8"
    },
    {
        "timestamp": 1558132444247,
        "result": "10"
    },
    {
        "timestamp": 1558132477916,
        "result": "10"
    },
    {
        "timestamp": 1558132596327,
        "result": "14"
    }
]

С таким ответом интерфейс React может анализировать, но я понимаю, что не использую потоковую передачу. Кто-то может возразить, что для такого простого примера бесполезно думать о потоковой передаче, но моя цель обучения действительно сосредоточена на понимании и правильном кодировании с помощью webflux + react consumming streams.

Наконец, после прочтения https://spring.io/blog/2017/02/23/spring-framework-5-0-m5-update Я изменил контроллер restcontroller webflux на создание APPLICATION_STREAM_JSON_VALUE, а также попытался произвести = "application / stream + json". Для обоих вариантов ответ restcontroller кажется потоком json, но снова React жалуется:

{"timestamp":1558126555269,"result":"8"}
{"timestamp":1558132444247,"result":"10"}
{"timestamp":1558132477916,"result":"10"}
{"timestamp":1558132596327,"result":"14"}

Ошибка на стороне React:

Unexpected token { in JSON at position 41

Подводя итог: я не нашел, как использовать из React контроллер Webflux Restcontroller, создающий потоки Json.

Возможно, возможный ответ - «измените React, используя эту библиотеку и используйте ее таким образом», или, может быть, ответ будет «код Webflux Restcontroller для возврата в этом формате». Кстати, после прочтения всех примеров, которые я нашел в теме React + Webflux, я застрял.

Другими словами, мой прямой вопрос: как использовать конечную точку webflux, производящую json-потоки из React?


person Jim C    schedule 23.05.2019    source источник


Ответы (2)


Вы пробовали использовать EventSource для использования потока? Вид позднего ответа, но, надеюсь, это может вам помочь.

const source = new EventSource('/api-stream-endpoint');

source.onmessage = function logEvents(event) {
      console.log(JSON.parse(data));
}
person danyPasillas    schedule 06.01.2021

Сервер, как и ожидалось, создает поток отдельных строк JSON; однако клиент получает их в одном запросе.

То есть клиент пытается разобрать { id: 1 } { id: 2 } и терпит неудачу на втором {.

Если вы переключите сервер на создание APPLICATION_JSON, сервер получит коллекцию [{ id: 1 }, { id:2 }], и она должна работать.

person Meltie    schedule 13.11.2019