星点工具箱:前端也能这么丝滑!Node Vue3 实现 SSE 流式文本输出
前端也能这么丝滑!Node + Vue3 实现 SSE 流式文本输出
引言
在现代 Web 应用中,我们经常需要从服务器获取数据并实时显示在页面上。传统的请求-响应模式在处理实时数据更新时效率不高,而 WebSocket 虽然功能强大,但实现相对复杂。今天,我将介绍一种更简单、更轻量级的实时通信技术——Server-Sent Events (SSE),并展示如何使用 Node.js 和 Vue3 实现流式文本输出,让你的前端应用也能丝滑般地展示实时数据!
什么是 SSE?
Server-Sent Events (SSE) 是一种服务器向客户端推送事件的技术。它允许服务器向客户端发送数据流,客户端可以实时接收并处理这些数据。与 WebSocket 相比,SSE 更简单、更轻量级,特别适合服务器到客户端的单向数据传输场景。
SSE 的主要特点:
- 基于 HTTP 协议,无需额外的端口
- 自动重连机制
- 文本消息格式简单(JSON 或纯文本)
- 单向通信(服务器→客户端)
Node.js 后端实现
首先,我们需要创建一个 Node.js 服务器来发送 SSE 消息。我们将使用 Express 框架来简化开发。
安装依赖
npm init -y
npm install express
创建 SSE 服务器
// server.js
const express = require('express');
const app = express();
const port = 3000;
// 设置 CORS,允许前端访问
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
// SSE 端点
app.get('/stream', (req, res) => {
// 设置 SSE 所需的响应头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 模拟发送流式数据
const sendMessages = () => {
const messages = [
"欢迎来到 SSE 演示!",
"这是一个流式文本输出的例子。",
"服务器会逐字发送文本内容。",
"你可以看到文本是如何逐字显示在页面上的。",
"这就是 SSE 的魅力所在!"
];
let messageIndex = 0;
let charIndex = 0;
const sendNextChar = () => {
if (messageIndex >= messages.length) {
// 所有消息发送完毕,关闭连接
res.write('data: {"done": true}\n\n');
res.end();
return;
}
const currentMessage = messages[messageIndex];
if (charIndex < currentMessage.length) {
// 发送一个字符
const char = currentMessage[charIndex];
res.write(`data: {"char": "${char}", "done": false}\n\n`);
charIndex++;
setTimeout(sendNextChar, 50); // 控制发送速度
} else {
// 当前消息发送完毕,发送换行符
res.write('data: {"char": "\\n", "done": false}\n\n');
messageIndex++;
charIndex = 0;
setTimeout(sendNextChar, 200); // 消息间暂停
}
};
// 开始发送
sendNextChar();
};
// 处理客户端断开连接
req.on('close', () => {
console.log('客户端断开连接');
res.end();
});
// 开始发送消息
sendMessages();
});
app.listen(port, () => {
console.log(`SSE 服务器运行在 http://localhost:${port}`);
});
Vue3 前端实现
现在,让我们创建一个 Vue3 应用来接收 SSE 流并显示文本。
安装依赖
npm create vue@latest
# 或者使用 Vue CLI
# vue create vue-sse-client
实现 SSE 客户端
<!-- App.vue -->
<template>
<div class="container">
<h1>SSE 流式文本演示</h1>
<div class="stream-container">
<div class="output" ref="output"></div>
<div class="cursor" :style="{ top: cursorPosition + 'px' }"></div>
</div>
<button @click="startStream" :disabled="isStreaming">
{{ isStreaming ? '接收中...' : '开始接收' }}
</button>
<button @click="clearOutput" :disabled="!outputText">清空</button>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const output = ref(null);
const outputText = ref('');
const isStreaming = ref(false);
const eventSource = ref(null);
const cursorPosition = ref(0);
const startStream = () => {
if (isStreaming.value) return;
isStreaming.value = true;
outputText.value = '';
cursorPosition.value = 0;
// 创建 EventSource 连接
eventSource.value = new EventSource('http://localhost:3000/stream');
eventSource.value.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.done) {
// 流结束
isStreaming.value = false;
eventSource.value.close();
return;
}
if (data.char === '\n') {
// 处理换行
outputText.value += '\n';
cursorPosition.value += 20; // 假设每行高度为20px
} else {
// 添加字符
outputText.value += data.char;
// 更新光标位置(简单估算)
cursorPosition.value = outputText.value.length * 10; // 假设每个字符宽度为10px
}
// 滚动到底部
setTimeout(() => {
if (output.value) {
output.value.scrollTop = output.value.scrollHeight;
}
}, 0);
} catch (error) {
console.error('解析 SSE 数据时出错:', error);
}
};
eventSource.value.onerror = (error) => {
console.error('SSE 错误:', error);
isStreaming.value = false;
if (eventSource.value) {
eventSource.value.close();
}
};
};
const clearOutput = () => {
outputText.value = '';
cursorPosition.value = 0;
};
// 组件卸载时关闭连接
onUnmounted(() => {
if (eventSource.value) {
eventSource.value.close();
}
});
</script>
<style scoped>
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
h1 {
color: #333;
text-align: center;
}
.stream-container {
position: relative;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
height: 300px;
overflow: hidden;
margin-bottom: 20px;
}
.output {
height: 100%;
overflow-y: auto;
white-space: pre-wrap;
word-wrap: break-word;
line-height: 1.5;
}
.cursor {
position: absolute;
left: 5px;
width: 2px;
height: 20px;
background-color: #42b983;
animation: blink 1s infinite;
}
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
}
button {
padding: 8px 16px;
margin-right: 10px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #3aa876;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
</style>
完整示例
将上述代码整合起来,我们就有了一个完整的 Node.js + Vue3 SSE 流式文本输出示例。
- 启动 Node.js 服务器:
node server.js
- 启动 Vue 应用:
npm run dev
- 在浏览器中访问 Vue 应用,点击"开始接收"按钮,你将看到文本逐字显示的效果!
实际应用场景
SSE 流式文本输出在许多场景中非常有用:
- 聊天应用:实时显示消息
- 代码编辑器:显示代码执行过程
- 文档协作:多人同时编辑文档
- 实时日志:显示服务器日志输出
- AI 对话:显示 AI 生成的回答过程
- 长任务进度:显示长时间运行任务的进度
总结
通过本文,我们学习了如何使用 Node.js 和 Vue3 实现 SSE 流式文本输出。SSE 是一种简单而强大的技术,特别适合服务器向客户端推送实时数据的场景。相比 WebSocket,SSE 更轻量级,实现更简单,适合大多数单向通信需求。
关键点回顾:
- SSE 基于 HTTP 协议,适合服务器到客户端的单向通信
- Node.js 后端需要设置特定的响应头来启用 SSE
- 前端使用 EventSource API 接收 SSE 流
- 可以通过控制发送速度来实现流式效果
希望这篇文章能帮助你理解 SSE 并在你的项目中应用它!如果你有任何问题或建议,欢迎在评论区留言。觉得有用就点个关注!我会持续分享更多实用工具和效率技巧。想直接体验?各类免费、开箱即用的在线工具,都在我的【星点工具箱】网站等你来玩!
更多推荐



所有评论(0)