Vue3實(shí)現(xiàn)SSE(Server-Sent?Events)連接
在現(xiàn)代 web 開(kāi)發(fā)中,Server-Sent Events (SSE) 是一種輕量級(jí)的技術(shù),允許服務(wù)器通過(guò) HTTP 持久連接向客戶端推送實(shí)時(shí)更新。在本文中,我們將探討如何在 Vue 3 應(yīng)用中實(shí)現(xiàn) SSE 連接,并處理接收到的消息。
什么是 SSE
SSE 是一種允許服務(wù)器向?yàn)g覽器推送事件的技術(shù)。與 WebSocket 不同,SSE 是單向的:服務(wù)器可以向客戶端發(fā)送數(shù)據(jù),而客戶端不能直接向服務(wù)器發(fā)送數(shù)據(jù)。SSE 適用于需要實(shí)時(shí)更新的應(yīng)用,比如聊天應(yīng)用、通知系統(tǒng)和實(shí)時(shí)數(shù)據(jù)監(jiān)控。
核心代碼示例
let retryCount = 0; const maxRetries = 5; // 最大重試次數(shù) const maxRetryDelay = 30000; // 最大重連時(shí)間,30秒 // 當(dāng)前用戶身份 const username = ref(""); // 初始化 SSE 連接 let eventSource: EventSource; const initializeSSE = () => { // 連接SSE // 定義SSE鏈接參數(shù) let url = import.meta.env.VITE_BASE_API + "/notification/socket_connection?username=" + encodeURIComponent(username.value); // 監(jiān)聽(tīng)連接打開(kāi)事件 eventSource = new EventSource(url); eventSource.onopen = () => { console.log("建立 SSE 連接成功"); }; // 監(jiān)聽(tīng)消息事件 eventSource.onmessage = event => { // 收到消息 chunk.value = JSON.parse(event.data); console.log("收到的類型:", chunk.value.notice_type, 222); // 根據(jù) 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: // 暫時(shí)擱置,用其他方法代替 if (storedRole.value !== "user") { reportEmail(); } break; default: console.warn("未知通知類型:", chunk.value.notice_type); } showNotify(); }; // 監(jiān)聽(tīng)錯(cuò)誤事件 eventSource.onerror = () => { console.error("SSE 連接發(fā)生錯(cuò)誤,嘗試重連..."); eventSource.close(); // 關(guān)閉當(dāng)前連接 handleReconnect(); // 嘗試重連 }; }; const handleReconnect = () => { if (username.value !== "") { console.log("連接已關(guān)閉, 嘗試重新連接"); if (retryCount < maxRetries) { retryCount++; const retryDelay = Math.min( 1000 * Math.pow(2, retryCount), maxRetryDelay ); // 計(jì)算重連延遲 setTimeout(initializeSSE, retryDelay); } else { showToast("網(wǎng)絡(luò)連接不穩(wěn)定,請(qǐng)檢查網(wǎng)絡(luò)或重新登錄。"); console.log("已達(dá)到最大重試次數(shù),停止重連。"); } } };
舉例:全局狀態(tài)管理消息總數(shù)
假設(shè)我們有三種通知類型:
點(diǎn)贊、評(píng)論、收藏
在userStore中進(jìn)行全局狀態(tài)管理,動(dòng)態(tài)更新消息數(shù)量:
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; // 最大重試次數(shù) const maxRetryDelay = 30000; // 最大重連時(shí)間,30秒 // 是否顯示SSE彈框 const noticeShow = ref(false); // 接收到的SSE消息 const chunk = ref(); // 當(dāng)前用戶身份 const username = ref(""); const storedRole = ref(""); // 系統(tǒng)最新一條通知 const systemData = ref({}); // 管理員最新一條通知 const managerData = ref({}); // 用戶未讀消息 const thumb = ref(0); const comment = ref(0); const star = ref(0); // 管理員未讀消息數(shù) const manager_count = ref(0); // 系統(tǒng)未讀消息數(shù) const system_count = ref(0); // 郵箱未讀消息數(shù) const email_count = ref(0); // 互動(dòng)通知 // 默認(rèn)活躍的tab欄 const activeTab = ref(0); // 總數(shù) // 使用計(jì)算屬性動(dòng)態(tài)獲取 total const total = computed(() => { return ( thumb.value + comment.value + star.value + manager_count.value + system_count.value ); }); // 通用的獲取未讀通知數(shù)量的函數(shù) 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("獲取通知時(shí)發(fā)生錯(cuò)誤:", error); } }; // 獲取系統(tǒng)消息 const systemNotice = () => { fetchNotificationCount(getSystemNotification, systemData, system_count); console.log(system_count.value); }; // 獲取管理員消息 const managerNotice = () => { fetchNotificationCount( getManagerNotification, managerData, manager_count ); }; // 獲取點(diǎn)贊通知的未讀消息數(shù)量 const userThumNotification = () => { fetchNotificationCount(getUserThumNotification, null, thumb); }; // 獲取評(píng)論通知的未讀消息數(shù)量 const userComNotification = () => { fetchNotificationCount(getUserComNotification, null, comment); }; // 獲取收藏通知的未讀消息數(shù)量 const userStarNotification = () => { fetchNotificationCount(getUserStarNotification, null, star); }; // 獲取舉報(bào)郵箱消息 const reportEmail = async () => { fetchNotificationCount(getreportEmail, null, email_count); }; // 獲取頁(yè)面消息 const userNotice = async () => { await Promise.all([ userThumNotification(), userComNotification(), userStarNotification() ]); }; // 初始化函數(shù) 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鏈接參數(shù) let url = import.meta.env.VITE_BASE_API + "/notification/socket_connection?username=" + encodeURIComponent(username.value); // 監(jiān)聽(tīng)連接打開(kāi)事件 eventSource = new EventSource(url); eventSource.onopen = () => { console.log("建立 SSE 連接成功"); }; // 監(jiān)聽(tīng)消息事件 eventSource.onmessage = event => { // 收到消息 chunk.value = JSON.parse(event.data); console.log("收到的類型:", chunk.value.notice_type, 222); // 根據(jù) 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: // 暫時(shí)擱置,用其他方法代替 if (storedRole.value !== "user") { reportEmail(); } break; default: console.warn("未知通知類型:", chunk.value.notice_type); } showNotify(); }; // 監(jiān)聽(tīng)錯(cuò)誤事件 eventSource.onerror = () => { console.error("SSE 連接發(fā)生錯(cuò)誤,嘗試重連..."); eventSource.close(); // 關(guān)閉當(dāng)前連接 handleReconnect(); // 嘗試重連 }; }; const handleReconnect = () => { if (username.value !== "") { console.log("連接已關(guān)閉, 嘗試重新連接"); if (retryCount < maxRetries) { retryCount++; const retryDelay = Math.min( 1000 * Math.pow(2, retryCount), maxRetryDelay ); // 計(jì)算重連延遲 setTimeout(initializeSSE, retryDelay); } else { showToast("網(wǎng)絡(luò)連接不穩(wěn)定,請(qǐng)檢查網(wǎng)絡(luò)或重新登錄。"); console.log("已達(dá)到最大重試次數(shù),停止重連。"); } } }; // 關(guān)閉 SSE 連接 const closeConnection = () => { eventSource.close(); console.log("SSE 連接已手動(dòng)關(guān)閉"); }; // 重置 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 } );
到此這篇關(guān)于Vue3實(shí)現(xiàn)SSE(Server-Sent Events)連接的文章就介紹到這了,更多相關(guān)Vue3 SSE連接內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue在取對(duì)象長(zhǎng)度length時(shí)候出現(xiàn)undefined的解決
這篇文章主要介紹了vue在取對(duì)象長(zhǎng)度length時(shí)候出現(xiàn)undefined的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06實(shí)例詳解Vue項(xiàng)目使用eslint + prettier規(guī)范代碼風(fēng)格
這篇文章主要介紹了Vue項(xiàng)目使用eslint + prettier規(guī)范代碼風(fēng)格,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-08-08Vue關(guān)于數(shù)據(jù)綁定出錯(cuò)解決辦法
這篇文章主要介紹了Vue關(guān)于數(shù)據(jù)綁定出錯(cuò)解決辦法的相關(guān)資料,需要的朋友可以參考下2017-05-05vue elementui tree 任意級(jí)別拖拽功能代碼
這篇文章主要介紹了vue elementui tree 任意級(jí)別拖拽功能代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08Vue3中導(dǎo)入和使用組件幾種常見(jiàn)方法(.vue文件)
組件是Vue.js最強(qiáng)大的功能之一, 組件可以擴(kuò)展HTML元素,封裝可重用的代碼,下面這篇文章主要介紹了Vue3中導(dǎo)入和使用組件幾種常見(jiàn)方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09Vue項(xiàng)目首屏性能優(yōu)化組件實(shí)戰(zhàn)指南
Vue眾所周知是一個(gè)輕量級(jí)的框架,源碼僅僅為72.9KB,但是也有它自己的缺點(diǎn),就是首屏加載會(huì)比較慢,這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目首屏性能優(yōu)化組件的相關(guān)資料,需要的朋友可以參考下2021-11-11vue 項(xiàng)目 iOS WKWebView 加載
這篇文章主要介紹了vue 項(xiàng)目 iOS WKWebView 加載問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04Vue Element前端應(yīng)用開(kāi)發(fā)之開(kāi)發(fā)環(huán)境的準(zhǔn)備工作
這篇文章主要介紹了Vue Element前端應(yīng)用開(kāi)發(fā)之開(kāi)發(fā)環(huán)境的準(zhǔn)備工作,對(duì)Vue感興趣的同學(xué),可以來(lái)學(xué)習(xí)一下2021-05-05Vue使用正則校驗(yàn)文本框?yàn)檎麛?shù)
這篇文章主要介紹了Vue使用正則校驗(yàn)文本框?yàn)檎麛?shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10vue-resource請(qǐng)求實(shí)現(xiàn)http登錄攔截或者路由攔截的方法
這篇文章主要介紹了vue-resource請(qǐng)求實(shí)現(xiàn)http登錄攔截或者路由攔截的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07