欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 美景 > SSE请求多种实现方式总结

SSE请求多种实现方式总结

2024/10/24 4:34:36 来源:https://blog.csdn.net/qq_48896417/article/details/141381281  浏览:    关键词:SSE请求多种实现方式总结

SSE请求多种实现方式总结

  • 什么是SSE
  • 一、怎么实现SSE请求(基础版本)
    • 1、前端实现:
      • 前端示例代码
    • 2、 nodejs 后端示例代码
    • 3、特点
  • 二、Fetch API实现SSE(升级版本)
    • 1、 node后端代码
    • 2、 前端Fecth请求实现
    • 3、特点
  • 三、Fecth结合EventSource实现SSE(终极版本)
    • 1、node后端代码示例
    • 2、前端代码示例
    • 3、特点
  • 四、总结


文前推荐一下👉
前端必备工具推荐网站(图床、API和ChatAI、智能AI简历、AI思维导图神器等实用工具):
站点入口:http://luckycola.com.cn/


什么是SSE

SSE(Server-Sent Events)是一种用于实现服务器主动向客户端推送数据的技术,也被称为“事件流”(Event Stream)。它基于 HTTP 协议,利用了其长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。

SSE 和 Socket 区别
SSE(Server-Sent Events)和 WebSocket 都是实现服务器向客户端实时推送数据的技术,但它们在某些方面还是有一定的区别。

适用于场景
chatGPT 返回的数据 就是使用的SSE 技术

实时数据大屏 如果只是需要展示 实时的数据可以使用SSE技术 而不是非要使用webSocket


一、怎么实现SSE请求(基础版本)

1、前端实现:

EventSource 对象是 HTML5 新增的一个客户端 API,用于通过服务器推送实时更新的数据和通知。在使用 EventSource 对象时,如果服务器没有正确地设置响应头信息(如:Content-Type: text/event-stream),可能会导致 EventSource 对象无法接收到服务器发送的数据。

前端示例代码

const sse = new EventSource('http://localhost:3000/api/sse' )sse.addEventListener('open', (e) => {console.log(e.target)
})
//对应后端nodejs自定义的事件名lol
sse.addEventListener('lol', (e) => {console.log(e.data)
})

2、 nodejs 后端示例代码

import express from 'express';
const app = express();
app.get('/api/sse', (req, res) => {res.writeHead(200, {'Content-Type': 'text/event-stream', //核心返回数据流'Connection': 'close'})const data = fs.readFileSync('./index.txt', 'utf8')const total = data.length;let current = 0;//mock sse 数据let time = setInterval(() => {console.log(current, total)if (current >= total) {console.log('end')clearInterval(time)return}//返回自定义事件名res.write(`event:lol\n`)/返回数据res.write(`data:${data.split('')[current]}\n\n`)current++}, 300)
})
app.listen(3000, () => {console.log('Listening on port 3000');
});

上面./index.txt的内容就是一些随机的测试文本,如下

悲索之人烈焰加身,堕落者 不可饶恕,我即是引路的灯塔,也是净化的清泉。
永恒燃烧的羽翼,带我脱离凡间的沉沦,圣火将你洗涤。
今由烈火审判,于光明中得救。
利刃在手,制裁八方!

3、特点

这是一个最基础的实现版本,但是存在一个问题:这种sse的实现方式只能是GET请求,所以对参数传递的长度会有严重的限制

比如在AI聊天场景这种方式就不太适合,其实我们也可以通过浏览器Fetch API实现SSE

二、Fetch API实现SSE(升级版本)

fetch 本身不直接支持流式输出,但你可以使用 ReadableStream 和 TextDecoder 等 Web Streams API 来实现类似的效果。

1、 node后端代码

代码如下(示例):

router.get("/sse", (req: Request, res: Response)=>{console.log('/sse')res.writeHead(200, {'Content-Type': 'text/event-stream', //核心返回数据流'Connection': 'close'})const data = fs.readFileSync(path.join(__dirname, '../../source/index.txt'), 'utf8');const total = data.trim().length;let current = 0;//mock sse 数据const time = setInterval(() => {console.log(current, total)if (current >= total) {console.log('end')res.write(`event:end\n`)res.write(`data:\n\n`);clearInterval(time)return}//返回自定义事件名res.write(`event:lol\n`)// 返回数据res.write(`data:${data.split('')[current]}\n\n`);current++}, 50)
});

2、 前端Fecth请求实现

代码如下(示例):

function streamOutput(msg) {// 发送 POST 请求fetch('/sse', {method:"POST",body:JSON.stringify({ "content": msg}),timeout: 0,dataType:"text/event-stream",headers:{"Content-Type":"application/json"},}).then(response => {// 检查响应是否成功if (!response.ok) {throw new Error('Network response was not ok');}// 返回一个可读流return response.body;}).then(body => {disableLoading();const reader = body.getReader();// 读取数据流function read() {return reader.read().then(({ done, value }) => {// 检查是否读取完毕if (done) {console.log('已传输完毕');return;}// 处理每个数据块console.log('收到的数据:', value);// 继续读取下一个数据块read();});}// 开始读取数据流read();}).catch(error => {console.error('Fetch error:', error);});
}

3、特点

这种方式的优点很直接可以支持POST请求方式来实现SSE效果,而且请求参数长度可以得到很大的拓展,符合长文本输入的需求.另外Fetch是浏览器原生API支持度好,简单易用.

三、Fecth结合EventSource实现SSE(终极版本)

这种方式结合了两种实现方式,是不是很特别,他的实现类似Websoket,后端需要通过保存前端的EventSource 队列来管理,我们直接上代码

1、node后端代码示例

const express = require('express');  
const router = express.Router();  let clients = [];  // 创建一个 SSE 端点  
router.get('/events', (req, res) => {  res.setHeader('Content-Type', 'text/event-stream');  res.setHeader('Cache-Control', 'no-cache');  res.setHeader('Connection', 'keep-alive');  // 发送初始消息  res.write('data: {"status": "connected"}\n\n');  // 将客户端添加到监听列表  clients.push(res);  req.on('close', () => {  // 客户端断开连接时从列表中移除  clients = clients.filter(client => client !== res);  console.log('Client disconnected');  });  // 保持连接打开  res.on('close', () => {  clients = clients.filter(client => client !== res);  });  
});  // 生成 PPT 并发送更新到所有客户端  
router.post('/sse', async (req, res) => {  let markdownContent = `这是语段测试文本\n\n成东南侧不对称\n\n呢哈哈哈哈哈哈哈哈`;const slideContents = markdownContent.split('\n\n');  for (let slideContent of slideContents) {  const event = JSON.stringify({   finish: false,content:  slideContent});  // 发送消息到所有连接的客户端  clients.forEach(client => {  if (client.writable) {  client.write(`data: ${event}\n\n`);  }  });  }  // 完成后可以发送一个完成消息,但通常 SSE 不需要这样做  // 因为客户端可以通过关闭连接来检测完成  let endEvent =  JSON.stringify({   finish: true,content:  ''});  client.write(`data: ${endEvent}\n\n`);  
});  module.exports = router;

2、前端代码示例

    <script>  // SSE连接  var evtSource = new EventSource('/events');  evtSource.onmessage = function(e) {  console.log("EventSource收到信息:", e.data) };  evtSource.onerror = function(e) {  console.error('EventSource failed:', e);  evtSource.close();  };  function sendMesssageFn() {  // 使用fetch API发送POST请求  fetch('/sse', {  method: 'POST', // 或者 'PUT'  headers: {  'Content-Type': 'application/json',  },  body: JSON.stringify(data), // 必须是JSON字符串  })  .then(response => {  if (!response.ok) {  throw new Error('Network response was not ok');  }  return response.text(); // 或者返回response.json()如果后端返回JSON  })  .then(text => {  // 这里假设后端返回纯文本消息  })  .catch(error => {  console.error('There was a problem with your fetch operation:', error);  });  
}sendMesssageFn();</script> 

3、特点

这种方式虽然也是通过fecth进行信息请求通信,但是不同的是他的消息监听仍然是通过EventSource实现的,所以不需要通过getReader解析信息.

四、总结

SSE是一种单工的通信方式,实现方式十分多样,每一种实现都有各自的优点缺点,应该根据需求进行合理的选择.

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com