如何使用Webflux端点从React

时间:2019-05-23 18:28:52

标签: reactjs async-await reactive-programming spring-webflux jsonstream

我想学习如何使用WebFlux restcontroller从React生成json流。我的第一个试探性迫使我解析为json的文本实例,但是我感觉自己在做一些奇怪的事情。我决定投入精力阅读周围的示例,并发现返回org.reactivestreams.Publisher而不返回WebFlux的示例。

我发现了一个较旧的主题可以帮助我(Unable to Consume Webflux Streaming Response in React-Native client),但是没有一个答案。好吧,这驱使我读到某个地方,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,是因为我认为我更喜欢返回流,因为我正在使用无阻塞代码,因此,我认为返回Webflux以便正确利用它更有意义,而不是返回org.reactivestreams.Publisher。 5春季以上的版本。

我的Webflux rest控制器:

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:JSON中位置0的意外令牌d”的原因:我没有返回有效的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 +反应消费流正确地理解和编码。

最后,在读取https://spring.io/blog/2017/02/23/spring-framework-5-0-m5-update之后,我将webflux restcontroller更改为产生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端点从React生成json流?

2 个答案:

答案 0 :(得分:1)

您是否尝试过使用 EventSource 来消费流? 回复有点晚,但希望能帮到你。

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

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

答案 1 :(得分:0)

服务器正在按预期生成单个JSON字符串流;但是,客户端是在一个请求中收到它们的。

也就是说,客户端正在尝试解析{ id: 1 } { id: 2 }并在第二个{上失败。

如果您将服务器切换为生产APPLICATION_JSON,则服务器将收到集合[{ id: 1 }, { id:2 }],它应该可以工作。