Vue3+ts sse封装

什么是 sse

SSE(Server-Sent Events)是一种基于 HTTP 协议,用于实现服务器主动向客户端推送数据的技术。它在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送,而客户端不能发送数据给服务端。

SSE是一种允许服务器向客户端单向发送数据的技术

和 websocket 不同 ,websocket 是客户端和服务器可以双向发送数据,sse 技术常用与 消息推送,websocket 常用与 聊天

为什么选择 sse

我最近写的是模仿 ai 的一个流式输出,前端需要做的就只是接收 后端所传递过来的若干数据,并且实现流式输出,重点是 : 我们只用接收,而不必去向服务器发送数据

使用 sse

sse 和 websocket 的方法差不多 提供的也是几个回调函数 onopen、onmessage、onerror 、onclose

vue3+ts 建立sse连接代码

ini 复制代码
const eventSource = ref<EventSource | null>();

const initSSE = () => {
  eventSource.value = new EventSource("http://地址");

  eventSource.value.onmessage = (event) => {
    console.log("收到消息内容是:", event.data);
  };

  eventSource.value.onerror = (error) => {
    console.error("SSE 连接出错:", error);
    eventSource.value!.close();
  };
};

onMounted(() => {
  initSSE();
});

onUnmounted(() => {
  if (eventSource) {
    eventSource.value?.close();
  }
});

然后 在实际运用过程中,我发现如上代码是get请求,实际开发中是 post 请求。sse 本身不支持 post 请求

于是我们需要借助 fetchEventSource 来实现 sse 的 post 请求

使用 fetchEventSource 建立 sse 的 post 请求

安装

css 复制代码
pnpm i @microsoft/fetch-event-source

使用

javascript 复制代码
await fetchEventSource(
    getForumAIUrl("你的地址",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json;charset=utf-8",
      },
      body: JSON.stringify({
        //你的数据,也可以不传
      }),
      openWhenHidden: true,
      onopen() {},
      onmessage(event) {
        isLoading.value = false;

        let data = JSON.parse(event.data);
        //处理业务逻辑
      },
      onerror(error) {
        console.error("SSE 连接出错:", error);
      },
    }
  );

以上就是建立了一个 sse 的 post 连接

但是我在写代码的过程中 ,又发现很多地方都需要用到这个 sse 技术,能不能给他封装起来,以便于我们更好的使用,于是我便开始了封装之路

封装 sse

思路: 考虑到 我们其实只需要传递 需要的url,方法,以及数据,有时候需要 在header 中设置 一些 key 来访问,并且我们大部分业务逻辑只关心 onmessage 事件的触发 和使用

在 utils 目录下 新建了 一个 sse.ts 文件

以下是所有的代码

typescript 复制代码
import { fetchEventSource } from "@microsoft/fetch-event-source";
import { ElMessage } from "element-plus";

// 定义消息回调类型
type MessageHandler = (data: any) => void;

export class SSEService {
  async connect(
    url: string,
    method: "GET" | "POST",
    body: object,
    onMessageHandler: MessageHandler,
    myHeader?: Record<string, string> // 键值对的形式
  ) {
    return await fetchEventSource(url, {
      method: method,
      headers: {
        "Content-Type": "application/json;charset=utf-8",
        ...myHeader, // 当 myHeader 未定义时会自动忽略展开
      },
      body: JSON.stringify(body),
      openWhenHidden: true,
      async onopen() {
        // 可以在这里添加连接成功逻辑
      },
      onmessage(event) {
        onMessageHandler(event);
      },
      onerror(error) {
        ElMessage.error("SSE连接出错: " + error);
      },
      onclose(){

      }
    });
  }
}

通过封装成 SSEService 类,并且在触发 onmessage 事件时,调用 我们传递进去的 函数,这样我们就可以使用,并且支持 headers 添加自己想要的内容

使用示例代码

ini 复制代码
 import { SSEService } from "@/utils/sse";

 let sse = new SSEService();

 sse.connect(
    getForumAIUrl(currentConversition.value!.id) +
      `?search_enabled=${isInternet.value}`,
    "POST",
    {
      query: sendText.value,
      stream: true,
      history: [],
    },
    (event: any) => {
      // 这里处理收到的消息
      let data = JSON.parse(event.data);
      console.log("收到SSE消息:", data);
      //下面的业务逻辑可以替换成你自己的
      isLoading.value = false;
      if (data?.done) {
        return;
      }

      if (data?.content) {
        let decodeContent = decodeUnicode(data!.content);
        console.log(decodeContent);

        handleRender(decodeContent);
      } else {
        setTimeout(() => {
          isLoading.value = false;
        });
      }
    }
  );

然后这就封装好并且使用了,不用每次都写 冗余的代码去建立 sse 连接了

相关推荐
慧一居士6 分钟前
flex 布局完整功能介绍和示例演示
前端
DoraBigHead8 分钟前
小哆啦解题记——两数失踪事件
前端·算法·面试
一斤代码6 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子6 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年6 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子6 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina6 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路7 小时前
React--Fiber 架构
前端·react.js·架构
伍哥的传说7 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409198 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app