Vue3实现SSE(Server-Sent Events)连接

 更新时间:2024年10月28日 15:06:16   作者:算是难了  
SSE 是一种允许服务器向浏览器推送事件的技术,这篇文章主要为大家详细介绍了如何通过vue3实现SSE(Server-Sent Events)连接,有需要的小伙伴可以了解下

在现代 web 开发中,Server-Sent Events (SSE) 是一种轻量级的技术,允许服务器通过 HTTP 持久连接向客户端推送实时更新。在本文中,我们将探讨如何在 Vue 3 应用中实现 SSE 连接,并处理接收到的消息。

什么是 SSE

SSE 是一种允许服务器向浏览器推送事件的技术。与 WebSocket 不同,SSE 是单向的:服务器可以向客户端发送数据,而客户端不能直接向服务器发送数据。SSE 适用于需要实时更新的应用,比如聊天应用、通知系统和实时数据监控。

核心代码示例

    let retryCount = 0;
    const maxRetries = 5; // 最大重试次数
    const maxRetryDelay = 30000; // 最大重连时间,30秒  
 
    // 当前用户身份
    const username = ref("");
 
    // 初始化 SSE 连接
    let eventSource: EventSource;
    const initializeSSE = () => {
      // 连接SSE
      // 定义SSE链接参数
      let url =
        import.meta.env.VITE_BASE_API +
        "/notification/socket_connection?username=" +
        encodeURIComponent(username.value);
      // 监听连接打开事件
      eventSource = new EventSource(url);
      eventSource.onopen = () => {
        console.log("建立 SSE 连接成功");
      };
 
      // 监听消息事件
      eventSource.onmessage = event => {
        // 收到消息
        chunk.value = JSON.parse(event.data);
        console.log("收到的类型:", chunk.value.notice_type, 222);
 
        // 根据 notice_type 处理不同的通知类型
        switch (chunk.value.notice_type) {
          case 0:
            userThumNotification();
            break;
          case 1:
            userStarNotification();
            break;
          case 2:
            userComNotification();
            break;
          case 3:
            systemNotice();
            break;
          case 4:
            managerNotice();
            break;
          case 5:
            // 暂时搁置,用其他方法代替
            if (storedRole.value !== "user") {
              reportEmail();
            }
            break;
          default:
            console.warn("未知通知类型:", chunk.value.notice_type);
        }
        showNotify();
      };
 
      // 监听错误事件
      eventSource.onerror = () => {
        console.error("SSE 连接发生错误,尝试重连...");
        eventSource.close(); // 关闭当前连接
        handleReconnect(); // 尝试重连
      };
    };
 
    const handleReconnect = () => {
      if (username.value !== "") {
        console.log("连接已关闭, 尝试重新连接");
        if (retryCount < maxRetries) {
          retryCount++;
          const retryDelay = Math.min(
            1000 * Math.pow(2, retryCount),
            maxRetryDelay
          ); // 计算重连延迟
          setTimeout(initializeSSE, retryDelay);
        } else {
          showToast("网络连接不稳定,请检查网络或重新登录。");
          console.log("已达到最大重试次数,停止重连。");
        }
      }
    };

举例:全局状态管理消息总数

假设我们有三种通知类型:

点赞、评论、收藏

在userStore中进行全局状态管理,动态更新消息数量:

import { defineStore } from "pinia";
import { ref, computed } from "vue";
import { getManagerNotification } from "@/api/user";
import { getreportEmail } from "@/api/user";
import { getSystemNotification } from "@/api/user";
import {
  getUserThumNotification,
  getUserComNotification,
  getUserStarNotification
} from "@/api/user";
import { showToast } from "vant";
// import { showNotify } from "vant";
//用户信息管理
export const useInformation = defineStore(
  "notication",
  () => {
    let retryCount = 0;
    const maxRetries = 5; // 最大重试次数
    const maxRetryDelay = 30000; // 最大重连时间,30秒
 
    // 是否显示SSE弹框
    const noticeShow = ref(false);
    // 接收到的SSE消息
    const chunk = ref();
 
    // 当前用户身份
    const username = ref("");
    const storedRole = ref("");
 
    // 系统最新一条通知
    const systemData = ref({});
    // 管理员最新一条通知
    const managerData = ref({});
 
    // 用户未读消息
    const thumb = ref(0);
    const comment = ref(0);
    const star = ref(0);
    // 管理员未读消息数
    const manager_count = ref(0);
    // 系统未读消息数
    const system_count = ref(0);
    // 邮箱未读消息数
    const email_count = ref(0);
 
    // 互动通知
    // 默认活跃的tab栏
    const activeTab = ref(0);
 
    // 总数
    // 使用计算属性动态获取 total
    const total = computed(() => {
      return (
        thumb.value +
        comment.value +
        star.value +
        manager_count.value +
        system_count.value
      );
    });
 
    // 通用的获取未读通知数量的函数
    const fetchNotificationCount = async (fetchFunction, refData, refCount) => {
      try {
        const res = await fetchFunction({ page: 1, limit: 1 });
        if (refData != null) {
          refData.value = res.data;
        }
        refCount.value = res.data.unread_count;
      } catch (error) {
        console.error("获取通知时发生错误:", error);
      }
    };
 
    // 获取系统消息
    const systemNotice = () => {
      fetchNotificationCount(getSystemNotification, systemData, system_count);
      console.log(system_count.value);
    };
 
    // 获取管理员消息
    const managerNotice = () => {
      fetchNotificationCount(
        getManagerNotification,
        managerData,
        manager_count
      );
    };
 
    // 获取点赞通知的未读消息数量
    const userThumNotification = () => {
      fetchNotificationCount(getUserThumNotification, null, thumb);
    };
 
    // 获取评论通知的未读消息数量
    const userComNotification = () => {
      fetchNotificationCount(getUserComNotification, null, comment);
    };
 
    // 获取收藏通知的未读消息数量
    const userStarNotification = () => {
      fetchNotificationCount(getUserStarNotification, null, star);
    };
 
    // 获取举报邮箱消息
    const reportEmail = async () => {
      fetchNotificationCount(getreportEmail, null, email_count);
    };
 
    // 获取页面消息
    const userNotice = async () => {
      await Promise.all([
        userThumNotification(),
        userComNotification(),
        userStarNotification()
      ]);
    };
 
    // 初始化函数
    const initNotifications = () => {
      console.log(username, "哈哈哈红红火火恍恍惚惚");
      systemNotice();
      managerNotice();
      userNotice();
      if (storedRole.value !== "user") {
        reportEmail();
      }
      // 打印 total,确保它是最新的
      console.log("Total after initialization:", total.value);
    };
 
    const showNotify = () => {
      noticeShow.value = true;
      setTimeout(() => {
        noticeShow.value = false;
      }, 3000);
    };
 
    // 初始化 SSE 连接
    let eventSource: EventSource;
    const initializeSSE = () => {
      // 连接SSE
      // 定义SSE链接参数
      let url =
        import.meta.env.VITE_BASE_API +
        "/notification/socket_connection?username=" +
        encodeURIComponent(username.value);
      // 监听连接打开事件
      eventSource = new EventSource(url);
      eventSource.onopen = () => {
        console.log("建立 SSE 连接成功");
      };
 
      // 监听消息事件
      eventSource.onmessage = event => {
        // 收到消息
        chunk.value = JSON.parse(event.data);
        console.log("收到的类型:", chunk.value.notice_type, 222);
 
        // 根据 notice_type 处理不同的通知类型
        switch (chunk.value.notice_type) {
          case 0:
            userThumNotification();
            break;
          case 1:
            userStarNotification();
            break;
          case 2:
            userComNotification();
            break;
          case 3:
            systemNotice();
            break;
          case 4:
            managerNotice();
            break;
          case 5:
            // 暂时搁置,用其他方法代替
            if (storedRole.value !== "user") {
              reportEmail();
            }
            break;
          default:
            console.warn("未知通知类型:", chunk.value.notice_type);
        }
        showNotify();
      };
 
      // 监听错误事件
      eventSource.onerror = () => {
        console.error("SSE 连接发生错误,尝试重连...");
        eventSource.close(); // 关闭当前连接
        handleReconnect(); // 尝试重连
      };
    };
 
    const handleReconnect = () => {
      if (username.value !== "") {
        console.log("连接已关闭, 尝试重新连接");
        if (retryCount < maxRetries) {
          retryCount++;
          const retryDelay = Math.min(
            1000 * Math.pow(2, retryCount),
            maxRetryDelay
          ); // 计算重连延迟
          setTimeout(initializeSSE, retryDelay);
        } else {
          showToast("网络连接不稳定,请检查网络或重新登录。");
          console.log("已达到最大重试次数,停止重连。");
        }
      }
    };
 
    // 关闭 SSE 连接
    const closeConnection = () => {
      eventSource.close();
      console.log("SSE 连接已手动关闭");
    };
 
    // 重置
    const removeNotification = () => {
      systemData.value = {};
      managerData.value = {};
      thumb.value = 0;
      star.value = 0;
      manager_count.value = 0;
      system_count.value = 0;
      email_count.value = 0;
      activeTab.value = 0;
    };
 
    return {
      username,
      storedRole,
      systemData,
      managerData,
      manager_count,
      system_count,
      email_count,
      thumb,
      comment,
      star,
      total,
      activeTab,
      noticeShow,
      chunk,
      systemNotice,
      managerNotice,
      userThumNotification,
      userComNotification,
      userStarNotification,
      reportEmail,
      closeConnection,
      removeNotification,
      initializeSSE,
      initNotifications
    };
  },
  {
    persist: true
  }
);

到此这篇关于Vue3实现SSE(Server-Sent Events)连接的文章就介绍到这了,更多相关Vue3 SSE连接内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • vue组件中点击按钮后修改输入框的状态实例代码

    vue组件中点击按钮后修改输入框的状态实例代码

    要求点击修改按钮之后部分输入框由禁用状态变为可用状态。下面我给大家分享一段实例代码基于vue组件中点击按钮后修改输入框的状态,需要的的朋友参考下
    2017-04-04
  • Vue3源码解读computed和watch

    Vue3源码解读computed和watch

    这篇文章主要为大家介绍了Vue3中的computed和watch源码解读分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • vue+elementUI中el-radio设置默认值方式

    vue+elementUI中el-radio设置默认值方式

    这篇文章主要介绍了vue+elementUI中el-radio设置默认值方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • vuex与map映射实现方法梳理分析

    vuex与map映射实现方法梳理分析

    Vuex中的映射允许您将state中的任何属性(state、getter、mutation和action)绑定到组件中的计算属性,并直接使用state中的数据,下面我们来详细了解
    2022-09-09
  • Vue3 Ref获取真实DOM学习实战

    Vue3 Ref获取真实DOM学习实战

    这篇文章主要为大家介绍了Vue3 Ref获取真实DOM学习实战示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • vue实现web滚动条分页

    vue实现web滚动条分页

    这篇文章主要为大家详细介绍了vue实现web滚动条分页,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • vue3.0+echarts实现立体柱图

    vue3.0+echarts实现立体柱图

    这篇文章主要为大家详细介绍了vue3.0+echarts实现立体柱图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • vue中如何动态拼接this后面的变量

    vue中如何动态拼接this后面的变量

    这篇文章主要介绍了vue中如何动态拼接this后面的变量问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • vue监听页面中的某个div的滚动事件并判断滚动的位置

    vue监听页面中的某个div的滚动事件并判断滚动的位置

    本文主要介绍了vue监听页面中的某个div的滚动事件并判断滚动的位置,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • vue 解决uglifyjs-webpack-plugin打包出现报错的问题

    vue 解决uglifyjs-webpack-plugin打包出现报错的问题

    这篇文章主要介绍了vue 解决uglifyjs-webpack-plugin打包出现报错的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08

最新评论