首页 > 其他分享 >使用SSE发送和接收流式数据

使用SSE发送和接收流式数据

时间:2024-09-09 15:53:10浏览次数:11  
标签:write res 流式 id 发送 eventSource SSE close event

背景

早期去玩了一下各个Ai厂商的免费额度(主要是国内的),虽然不是很给力,但是还是蛮好玩的。
建立长连接我们通常使用WebSocket,而对于流式数据发送,只需要服务器返回数据,而不需要客户端发送数据的情况下,SSE是一个不错的选择。

介绍

SSE(Server-Sent Events)。
数据格式大致如下,如果不写明event,那么默认为message事件。

\n是必须的,可以看看阮一峰的文章,讲得比较详细。
https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html

id: 12\n
event: myEvent\n
retry: 10000\n
data: {name: zhangsan, age: 18, sex: male}\n\n

demo

node服务端

const http = require("http");
const fs = require("fs");

http
  .createServer((req, res) => {
    const url = req.url;
    if (url.includes("/sse")) {
      res.writeHead(200, {
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
        Connection: "keep-alive",
        "Access-Control-Allow-Origin": "*", // 允许跨域
      });

      // 每隔 1 秒发送一条消息
      let id = 0;
      const intervalId = setInterval(() => {
        // 这是我们想要返回的数据
        const data = {
          id,
          time: new Date(),
          body: "哈喽",
        };
        res.write(`id: ${id}\n\n`);
        res.write("event: message\n\n");
        res.write("retry: 10000\n\n");
        res.write("data: " + JSON.stringify(data) + "\n\n");
        console.log("当前id是: ", id);
        // 0到4,发送5条消息打算关闭连接
        if (id >= 4) {
          clearInterval(intervalId);
          res.write(`id: ${id}\n`);
          res.write("event: close\n");
          res.write("retry: 10000\n");
          res.write("data: " + JSON.stringify(data) + "\n\n");
          console.log("服务端发送完毕,请求关闭");
          res.end();
        }
        id++;
      }, 1000);

      // 当客户端关闭连接时停止发送消息
      req.on("close", () => {
        clearInterval(intervalId);
        id = 0;
        res.end();
      });
    } else {
      // 如果请求的路径无效,返回 404 状态码
      res.writeHead(404);
      res.end();
    }
  })
  .listen(3001);

console.log("Server listening on port 3001");

客户端

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>

      let eventSource;
      // 断开 SSE 连接
      const closeSSE = () => {
        eventSource.close();
        console.log(`SSE 连接关闭,状态${eventSource.readyState}`);
      };
      // 建立 SSE 连接
      const connectSSE = () => {
        eventSource = new EventSource("http://127.0.0.1:3001/fetch-sse");
        eventSource.onopen = () => {
          console.log(`SSE 连接成功,状态${eventSource.readyState}`);
        };

        eventSource.onerror = () => {
          console.log(`SSE 连接错误,状态${eventSource.readyState}`);
          eventSource.close();
        };
        eventSource.onmessage = (event) => {
          console.log('将字符串转化为json对象:',JSON.parse(event.data))
        };
        eventSource.addEventListener("close", (event) => {
          console.log('close事件: ',event);
          closeSSE();
        });
      };
      connectSSE()
    </script>
  </body>
</html>

测试

服务端文件为server.js,在当前文件夹打开终端,输入如下命令可以开启服务器。

node ./server.js

使用live-server等方式,打开index.html,这个应该都熟悉。
image

打开浏览器,打开控制台

注意

可以看到eventSource对象没有onclose钩子,因此存在一些问题。
image
当服务端发送完消息后,断开连接,而客户端却认为消息没发送完,于是重连,这样会造成不断的重连,而且还会判定为error,触发onerror钩子。

解决重连问题

解决这个方法,我们可以自定义一个close事件,让服务端发送消息,提醒客户端应该断开连接。
以下为关键代码

// 服务端
res.write("event: close\n");
res.write("data: " + JSON.stringify(data) + "\n\n");

注意closeSSE是前面自定义的方法,并不是标准API

// 客户端
eventSource.addEventListener("close", (event) => {
	console.log("close事件: ", event);
	closeSSE();
});

效果

image

结语

当初踩了些坑,希望之后能少踩一点。

标签:write,res,流式,id,发送,eventSource,SSE,close,event
From: https://www.cnblogs.com/oldsaltfish/p/18404647

相关文章

  • COSC3088 Essentials of IT and Ethics
    COSC3088EssentialsofITandEthicsAssessmentTask2:MultimediaLinkedInResourceCourseCode: COSC3088Weighting: Thisassessmentisworth40%ofyourfinalmarkforthisCourseLength: 1000-wordvisualresourceora3-minutevideo(+/-10%)Taskappr......
  • 推荐一个Python流式JSON处理模块:streaming-json-py
    每天,我们的设备、应用程序和服务都在生成大量的数据流,这些数据往往大多是以JSON格式存在的。如何高效地解析和处理这些JSON数据流是一大挑战。今天,我要为大家介绍一个能极大简化这一过程的利器:streaming-json-pystreaming-json-py介绍streaming-json-py是一个专为实时......
  • Jquery通过Ajax发送数据2
    一、低级Ajax方法   启动Ajax通信的方法,在内部jQuery会把这些方法都映射成$.ajax()全局函数的一种变体    $('#dictionary').load('a.html')加载HTML片段    等价    $.ajax({      url:  'a.html',      success: ......
  • JQuery通过Ajax发送数据
    JQuery的基础教程   第六章:通过Ajax发送请求   html代码<!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <metaname="viewport"content="width=device-width,initial-scale=1.0"&g......
  • 流式输出的三两方法
    第一种前提是类似于这样的数据对象结构{content:'这里是返回你的回答结果',displayText:'这里是返回你的回答结果'},用一个函数//打字效果函数constdisplayTextEffect=(index)=>{leti=0constspeed=100//字符输出速度,单位是毫秒constfu......
  • SpringBoot发送邮件
    0导入发送邮件的依赖包<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId></dependency>1获取邮件授权码2配置yml文件spring:mail:#smtp服务主机qq邮箱则为smtp.qq.comhost:s......
  • Vue2 - 详细实现聊天室IM即时通讯及聊天界面,支持发送图片视频、消息已读未读等,集成mqt
    前言如果您需要Vue3版本,请访问在vue2|nuxt2项目开发中,详解手机移动端H5网页在线1v1聊天功能(仿腾讯云IM功能),技术栈为MQTT通讯协议+后端Node服务端+数据库设计+vue前端聊天界面,超详细前后端完整流程及示例源代码,vue2聊天即时通讯IM实时接收和发送消息,可发送文字、图......
  • CSSE7610  The algorithm  exclusive acces
    CSSE7610        Assignment 11.  A bounded buffer is frequently implemented as a circular buffer, which isan array that is indexed modulo its length: One variable,in,containstheindexofthefirstemptyspaceandan......
  • DataX实战之MongoDB导入数据到mysql——打包jar包时出现Could not find goal assembly
    使用idea打开我们本地的datax源码或者下载的源码下载地址:https://github.com/alibaba/DataX/blob/master/mongodbreader/doc/mongodbreader.md进行编译,打包上传:指定mongodbreader模块以及它所依赖的模块进行打包【推荐使用,大约只运行3分钟左右】mvn-Ucleanpac......
  • CPU亲和性设置视频解析,代码示例 sched_setaffinity sched_getaffinity, CPU_ZERO、CP
    视频教程在这:cpu亲和性设置,NCCL,sched_setaffinitysched_getaffinity,CPU_ZERO、SET、ISSET、linux_哔哩哔哩_bilibili一、CPU亲和性简介CPU亲和性(CPUAffinity)设置是操作系统中一个重要的性能优化手段,它允许程序或进程被绑定到特定的CPU核心上运行。这样做的好处包括减少缓存未命中......