聊天问答文字逐步显示实现

后端

后端通过事件流逐步发送数据 (SSE),需要设置响应头的Content-Type为'text/event-stream'

SSE是一种服务器推送技术,适合单向流式传输

node示例代码

js 复制代码
const express = require('express');
const app = express();
const port = 3000;

app.get('/stream', (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    const text = "嗯,我现在要了解一下合规法规方面的知识。";
    let index = 0;

    const interval = setInterval(() => {
        if (index < text.length) {
            res.write(`data: ${text.charAt(index)}\n\n`); // 逐步发送字符
            index++;
        } else {
            clearInterval(interval);
            res.end(); // 结束流
        }
    }, 100); // 每 100ms 发送一个字符

});

  


app.listen(port, () => {
    console.log(`后端服务运行在 http://localhost:${port}`);
});

前端

1.可以通过EventSource接收流式数据,通过onmessage事件监听数据,并逐字显示

注意:这种方式只能处理get请求,且无法自定义请求头或请求体

示例:

js 复制代码
<body>
    <div id="answer"></div>
    <script>
        const answerElement = document.getElementById('answer');
        // 创建 SSE 连接
        const eventSource = new EventSource('http://localhost:3000/stream');
        // 监听数据事件
        eventSource.onmessage = (event) => {
           answerElement.textContent += event.data; // 逐步显示数据
        };

        // 监听流结束事件
        eventSource.onerror = () => {
            eventSource.close(); // 关闭连接
            console.log('流已结束');
        };
    </script>
</body>

2.使用fetch + ReadableStream

注意:如果是post请求,需要使用fetch。当然XHR也可以通过 progress 事件实现对后端返回的流式数据的解析,但需要注意数据完整性和性能问题。如果需要更强大的流式数据处理能力,推荐使用 fetch + ReadableStream

  1. ReadableStream

    • 通过 response.body.getReader() 获取 ReadableStream 的读取器。

    • 使用 reader.read() 逐块读取数据。

  2. 解码数据

    • 使用 TextDecoder 将二进制数据解码为字符串。

示例:

js 复制代码
<body>
  <div id="output"></div>
  <div id="loading">Loading...</div>

  <script>
    const outputElement = document.getElementById('output');
    const loadingElement = document.getElementById('loading');

    async function fetchStreamingData() {
      const url = 'http://localhost:3000/postStream'; // 后端接口地址
      const token = 'your-auth-token'; // 鉴权 token
      const data = { key1: 'value1', key2: 'value2' }; // 请求参数

      loadingElement.style.display = 'block'; // 显示加载动画

      try {
        const response = await fetch(url, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data),
        });

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        const reader = response.body.getReader();
        const decoder = new TextDecoder('utf-8');

        while (true) {
          const { done, value } = await reader.read();
          if (done) break;

          const chunk = decoder.decode(value, { stream: true });
          for (const char of chunk) {
            outputElement.textContent += char;
            outputElement.scrollTop = outputElement.scrollHeight; // 自动滚动
          }
        }
      } catch (error) {
        console.error('Error:', error);
        outputElement.textContent = 'Failed to load streaming data.';
      } finally {
        loadingElement.style.display = 'none'; // 隐藏加载动画
      }
    }

    fetchStreamingData();
  </script>
</body>

好啦😊已基本实现啦!当前实际开发中肯定还有一些细节需要注意,比如服务端返回的流式数据的格式,另外大多数内容都是markdown语法,如何把文本的语法格式渲染在html页面上,这些都是需要注意的哟

相关推荐
程序员黑豆18 分钟前
Java包装类:基本类型与对象的桥梁
java·前端·ai编程
bugcome_com3 小时前
JWT 知识小课堂:从入门到精通,一文吃透 JSON Web Token
前端·json
To_OC3 小时前
写了三天 Next.js,我的 React 世界观被拆了又装回去
前端·全栈·next.js
独泪了无痕3 小时前
viewer.js 安装与配置指南:实现图片预览功能
前端·vue.js
Fluxart.ai6 小时前
电商商品图审核怎么自动化?规则引擎、人工复核与发布门禁
java·前端·自动化
why技术6 小时前
AI 写的文章,可能都带着手敲一遍都去不掉的“隐形水印”。
前端·人工智能·后端
愚公搬代码6 小时前
【愚公系列】《Android应用案例开发大全》016-LBS类应用掌上杭州(辅助工具类的开发)
android·前端
CodeSheep6 小时前
又一个华为天才少年,离职了!
前端·后端·程序员
kyriewen6 小时前
面试官说"打开你的AI工具"——我才发现,他考的根本不是写代码
前端·人工智能·面试
IT_陈寒8 小时前
Vue的双向绑定把我坑惨了,原来这个场景不能用
前端·人工智能·后端