后端流式数据接收并渲染到页面上

问题描述:

一开始怎么也接收不到数据,在vite.config配置的代理如下

server: {
    proxy: {
      'api': {
        target:'http://172.21.80.115:10021',
        changeOrigin:true,
        rewrite: (path) => path.replace(/^\/sage-ddiligence-application/, '/sage-ddiligence-application'), // 重写路径
      }
    }
  }

把api那里改成

server: {
    proxy: {
      '/sage-ddiligence-application': {
        target:'http://172.21.80.115:10021',
        changeOrigin:true,
        rewrite: (path) => path.replace(/^\/sage-ddiligence-application/, '/sage-ddiligence-application'), // 重写路径
      }
    }
  }

就可以了,原因暂时还不知道

现在是不知道怎么接收流式数据,接收到的数据仍然是一次性显示出来的

const recept= async()=>{
    let res=await axios.get('/sage-ddiligence-application/customers/stream',{
      responseType: 'stream'
    })
    console.log(res.data)
}
recept()

解决方法:

(仅用两个数据渲染作示例)

1.发起 fetch 请求

  • 使用 fetch 函数向服务器请求数据流,其中 /sage-ddiligence-application/customers/stream 是数据流的URL。
  • 设置请求方法为 GET,并指定 Content-Typeapplication/json;charset=UTF-8,告诉服务器期望的响应数据类型是JSON。
const resp = await fetch('/sage-ddiligence-application/customers/stream', {
    method: 'GET',
    headers: {
      "Content-Type": "application/json;charset=UTF-8",
    },
  });

2.获取响应流的读取器:

  • 通过 await resp.body.getReader() 获取响应体(resp.body)的读取器(reader),这个读取器用于逐块读取数据流。
const reader = await resp.body.getReader();

3.创建 TextDecoder 实例:

  • TextDecoder 用于将流中接收到的字节序列(通常是 Uint8Array)解码成字符串。这里使用默认的 UTF-8 编码。
    const decoder = new TextDecoder();

4.定义并调用 read 函数:

  • read 是一个异步递归函数,用于从流中读取数据块,处理它们,并等待下一个数据块的到来。
  • 使用 await reader.read() 读取流中的下一块数据。reader.read() 返回一个Promise,该Promise解析为一个对象,其中包含两个属性:donevaluedone 是一个布尔值,表示是否已经读取了流的所有数据。value 是一个 Uint8Array,包含了读取到的数据块。
  • 如果 donetrue,表示流结束,打印 "Stream completed" 并返回,递归调用停止。
  • 使用 decoder.decode(value, {stream: true}) 将读取到的数据块 value 解码成字符串。设置 {stream: true} 表示解码器应保持内部状态,以便正确处理跨多个块的字符。 
async function read() {
    const {done, value} = await reader.read();
    if (done) {
      console.log("Stream completed");
      return;
    }
const str = decoder.decode(value, {stream: true});

5.处理解码后的字符串:

  • 将解码后的字符串 str 按换行符分割成多行,每行代表一个JSON对象(假设服务器按行发送JSON对象)。
  • 遍历每行字符串,使用 JSON.parse(line) 将其解析成JSON对象 data
  • 根据 data.attribute 的值,将 data.value 存储到相应的响应式变量中(例如,customerCodecustomerNames)。
  • 使用 str.split('\n') 将字符串 str 分割成数组:这里,str 是一个包含多行的字符串,每行可能代表一个独立的JSON对象。通过使用 .split('\n') 方法,我们可以根据换行符将这个字符串分割成一个数组,数组中的每个元素都是原字符串中的一行。

  • 对结果数组使用 .forEach(...) 进行迭代:分割操作返回的数组可以使用 .forEach 方法。这个方法接受一个回调函数作为参数,该回调函数会被数组中的每个元素依次调用。在这个回调函数内,你可以处理每一行字符串,解析JSON并更新相应的响应式变量。

  • //假设每个json对象都是换行传过来的
        str.split('\n').forEach(line => {
          if (line) {
            const data = JSON.parse(line);
            if (data.attribute === 'customerCode') {
              customerCode.value = data.value;
            } else if (data.attribute === 'customerName') {
              customerNames.value.push(data.value);
            }
          }
        });

    6.递归读取下一个数据块:

  • read 函数的末尾,递归调用 read() 函数本身,开始读取下一个数据块,直到整个流被读完。

7.完整代码

<script>
async function getData() {
  const resp = await fetch('/sage-ddiligence-application/customers/stream', {
    method: 'GET',
    headers: {
      "Content-Type": "application/json;charset=UTF-8",
    },
  });
  const reader = await resp.body.getReader();
  const decoder = new TextDecoder();
  async function read() {
    const {done, value} = await reader.read();
    if (done) {
      console.log("Stream completed");
      return;
    }
    const str = decoder.decode(value, {stream: true});
    //假设每个json对象都是换行传过来的
    str.split('\n').forEach(line => {
      if (line) {
        const data = JSON.parse(line);
        if (data.attribute === 'customerCode') {
          customerCode.value = data.value;
        } else if (data.attribute === 'customerName') {
          customerNames.value.push(data.value);
        }
      }
    });
    read();
  }
  read();
}


getData()
</script>

<template>
<div class="table-cell">{{ customerCode }}</div>
<div class="table-cell">{{ customerNames.join('') }}</div>
</template>

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在uni-app中接收后端返回的数据,可以使用WebSocket或者长连接的方。 1. WebSocket方: 在uni-app中,可以使用uni.createSocket()方法创建WebSocket对象,通过监听onMessage事件来接收后端返回的数据。示例代码如下: ```javascript // 创建WebSocket对象 const socket = uni.createSocket({ url: 'ws://xxx.xxx.xxx.xxx:xxxx', // WebSocket地址 header: { 'content-type': 'application/json' } }) // 监听WebSocket连接成功事件 socket.onOpen((res) => { console.log('WebSocket连接已打开!') }) // 监听WebSocket接收到消息事件 socket.onMessage((res) => { console.log('接收到消息:', res) }) // 监听WebSocket错误事件 socket.onError((res) => { console.log('WebSocket连接错误:', res) }) // 监听WebSocket关闭事件 socket.onClose((res) => { console.log('WebSocket连接已关闭!') }) // 关闭WebSocket连接 socket.close() ``` 2. 长连接方: 在uni-app中,可以使用uni.connectSocket()方法创建长连接对象,通过监听onSocketMessage事件来接收后端返回的数据。示例代码如下: ```javascript // 创建长连接对象 const socketTask = uni.connectSocket({ url: 'ws://xxx.xxx.xxx.xxx:xxxx', // 长连接地址 header: { 'content-type': 'application/json' } }) // 监听长连接连接成功事件 socketTask.onOpen((res) => { console.log('长连接已打开!') }) // 监听长连接接收到消息事件 socketTask.onMessage((res) => { console.log('接收到消息:', res) }) // 监听长连接错误事件 socketTask.onError((res) => { console.log('长连接错误:', res) }) // 监听长连接关闭事件 socketTask.onClose((res) => { console.log('长连接已关闭!') }) // 关闭长连接 socketTask.close() ``` 以上是两种接收后端返回的数据的方,具体使用哪种方,需要根据接口返回的数据类型以及业务需求来决定。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值