在传统的前端开发模式下,数据通常是批量加载,等待所有数据加载完成后再一次性呈现给用户。然而,随着大数据和实时应用的崛起,这种一次性加载的方式往往会导致页面加载时间过长,用户体验大打折扣。流式输出则提供了一种全新的解决方案,它允许数据分批加载并在接收到每一部分数据时立即更新视图,从而显著提升了页面响应速度和用户满意度。在接下来的内容中,我将讲述如何在Vue2中,利用SSE技术来实现流式输出。

流式输出是一种数据处理和传输方式,它允许数据源连续不断地向接收端发送数据,而无需等待整个数据集准备完毕。在流式输出中,数据可以像水流一样源源不断地传输。在这种模式下,用户可以迅速开始观看或监听,而无需等到所有数据都加载完毕。
流式输出示例

1、SSE技术介绍
SSE (Server-Sent Events)即服务器推送事件,是一种基于HTTP的服务器推送技术。它允许服务器实时地向客户端推送数据。在SSE中,客户端通过创建一个EventSource对象来监听来自服务器的事件流。一旦连接建立,服务器就可以开始发送事件到客户端。客户端可以通过监听特定的事件类型来处理这些消息,并在需要时执行相应的操作。

   SSE工作原理
   1、建立连接:
   客户端通过在HTTP请求中设置Accept: text/event-stream来表明其期望接收SSE。
   服务器响应一个持久连接,通常使用HTTP的Content-Type: text/event-stream和Connection: keep-alive头。

   2、数据传输:
   服务器通过这个连接发送事件流,每条事件由三部分组成:
        •  event字段:可选,用于标识事件类型。
        •  data字段:必需,包含实际的数据内容。
        •  id字段:可选,用于客户端确认消息的顺序或重播。
         每条事件之间用换行符分隔,每个字段之间用冒号和空格分隔。


   示例事件流:
   event: myEvent
   data: {"message": "Hello, World!"}
   id: 123
   
   3、客户端处理:
   浏览器会自动处理接收到的事件流,并触发一个eventSource对象的message事件。开发者可以注册事件监听器来处理这些事件。

2、数据准备
本文后端的数据来源是使用Python代码,基于Flask框架进阶实现。

   在此仅仅强调四点。
   1、 返回数据response的响应头中的Content-Type应该设置成text/event-stream。
   2、返回数据response的响应头中的Cache-Control应该设置成no-cache。
   3、 数据响应要有一个结尾标识"done"。以便于数据流断开链接,避免重复发起请求。
   4、 跨域尽量再后端进行处理,如果跨域再前端处理的话,会出现数据等待,进而无法实现流式输出的效果。

3、关键方法实现

connectToSSE() {
  this.eventSource = new EventSource('http://127.0.0.1:5000/llm/request');
  
  this.eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data)//将字符串转换成json格式
    if (data.number !== 'done') {
      this.numbers.push(data.number);
    } else {
      this.eventSource.close();
    }
  };
  
  this.eventSource.onerror = (error) => {
    if (this.eventSource.readyState === EventSource.CLOSED) {
      console.log('Connection to server closed');
    } else {
      console.error('Error occurred:', error);
    }
  };
}

4、代码解析

  • 1、使用new EventSource(url)创建对象。url表示请求数据的地址。
  • 2、this.eventSource.onmessage = (event) => {}当服务器发送新的SSE事件时,onmessage
  • 事件处理器会被触发。我们在这里对于业务逻辑进行主要编写。比如数据对象的补充。
  • 3、如果返回的数据为结束标识符"done",则关闭与SSE源的连接。避免请求多发和资源浪费。
  • 4、this.eventSource.onerror = (error) =>{}如果SSE连接出现错误,onerror
    事件处理器会被触发。及时的关闭数据流,避免长时间的等待,占用内存。
    -5、F12,看一下具体请求头和响应头信息。

6、完整代码

<template>
  <div style="display: flex">
    <div v-for="(number, index) in numbers" :key="index"> {{ number }} </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      numbers: [],
      eventSource: null,
    };
  },
  created() {
    this.connectToSSE();
  },
  methods: {
    connectToSSE() {
      this.eventSource = new EventSource('http://127.0.0.1:5000/llm/request');
      this.eventSource.onmessage = (event) => {
        const data = JSON.parse(event.data) //将字符串转换成json格式
        if (data.number !== 'done') { //判断结束标识
          this.numbers.push(data.number);
        } else {
          this.eventSource.close();
        }
      };
      this.eventSource.onerror = (error) => {
        if (this.eventSource.readyState === EventSource.CLOSED) {
          console.log('Connection to server closed');
        } else {
          console.error('Error occurred:', error);
        }
      };
    }
  },
  beforeDestroy() {
    if (this.eventSource) {
      this.eventSource.close();
    }
  },
};
</script>
最后修改:2024 年 09 月 13 日
如果觉得我的文章对你有用,请随意赞赏