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 连接了

相关推荐
崔庆才丨静觅13 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606114 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了14 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅14 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅14 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅15 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment15 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅15 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊15 小时前
jwt介绍
前端
爱敲代码的小鱼15 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax