From 5be8fcf5719dfa49dfc8363b7118411d2bfade06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Thu, 26 Mar 2026 17:25:36 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E9=87=8D=E6=9E=84=20common-sse=20?= =?UTF-8?q?=E4=B8=8E=20common-websocket=20=E5=90=88=E5=B9=B6=E4=B8=BA=20ru?= =?UTF-8?q?oyi-common-push=20=E6=8E=A8=E9=80=81=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 11 ++-- .env.production | 11 ++-- src/api/login.ts | 9 +++- src/layout/index.vue | 10 +--- src/types/env.d.ts | 5 +- src/utils/push.ts | 113 +++++++++++++++++++++++++++++++++++++++++ src/utils/sse.ts | 53 ------------------- src/utils/websocket.ts | 62 ---------------------- 8 files changed, 139 insertions(+), 135 deletions(-) create mode 100644 src/utils/push.ts delete mode 100644 src/utils/sse.ts delete mode 100644 src/utils/websocket.ts diff --git a/.env.development b/.env.development index bc93332..9a0d656 100644 --- a/.env.development +++ b/.env.development @@ -29,8 +29,11 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C # 客户端id VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e' -# websocket 开关 默认使用sse推送 -VITE_APP_WEBSOCKET = false +# 统一消息推送开关 +VITE_APP_MESSAGE_ENABLED = true -# sse 开关 -VITE_APP_SSE = true +# sse / websocket +VITE_APP_MESSAGE_TRANSPORT = 'sse' + +# 统一消息推送路径 +VITE_APP_MESSAGE_PATH = '/resource/message' diff --git a/.env.production b/.env.production index e5532de..edce743 100644 --- a/.env.production +++ b/.env.production @@ -32,8 +32,11 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C # 客户端id VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e' -# websocket 开关 默认使用sse推送 -VITE_APP_WEBSOCKET = false +# 统一消息推送开关 +VITE_APP_MESSAGE_ENABLED = true -# sse 开关 -VITE_APP_SSE = true +# sse / websocket +VITE_APP_MESSAGE_TRANSPORT = 'sse' + +# 统一消息推送路径 +VITE_APP_MESSAGE_PATH = '/resource/message' diff --git a/src/api/login.ts b/src/api/login.ts index 37e5ff6..134ecfa 100644 --- a/src/api/login.ts +++ b/src/api/login.ts @@ -2,6 +2,7 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; import { LoginData, LoginResult, VerifyCodeResult } from './types'; import { UserInfo } from '@/api/system/user/types'; +import { closePush } from '@/utils/push'; // pc端固定客户端授权id const clientId = import.meta.env.VITE_APP_CLIENT_ID; @@ -51,9 +52,13 @@ export function register(data: any) { * 注销 */ export function logout() { - if (import.meta.env.VITE_APP_SSE === 'true') { + closePush(); + if ( + import.meta.env.VITE_APP_MESSAGE_ENABLED === 'true' + && import.meta.env.VITE_APP_MESSAGE_TRANSPORT.toLowerCase() !== 'websocket' + ) { request({ - url: '/resource/sse/close', + url: import.meta.env.VITE_APP_MESSAGE_PATH + '/close', method: 'get' }); } diff --git a/src/layout/index.vue b/src/layout/index.vue index 34b0ef3..10a4762 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -19,8 +19,7 @@ import { AppMain, Navbar, Settings, TagsView } from './components'; import { useAppStore } from '@/store/modules/app'; import { useSettingsStore } from '@/store/modules/settings'; import { NavTypeEnum } from '@/enums/NavTypeEnum'; -import { initWebSocket } from '@/utils/websocket'; -import { initSSE } from '@/utils/sse'; +import { initPush } from '@/utils/push'; const settingsStore = useSettingsStore(); const theme = computed(() => settingsStore.theme); @@ -61,12 +60,7 @@ watchEffect(() => { const settingRef = ref>(); onMounted(() => { - const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; - initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket'); -}); - -onMounted(() => { - initSSE(import.meta.env.VITE_APP_BASE_API + '/resource/sse'); + initPush(); }); const handleClickOutside = () => { diff --git a/src/types/env.d.ts b/src/types/env.d.ts index 1fb9f62..e6262d5 100644 --- a/src/types/env.d.ts +++ b/src/types/env.d.ts @@ -18,8 +18,9 @@ interface ImportMetaEnv { VITE_APP_RSA_PUBLIC_KEY: string; VITE_APP_RSA_PRIVATE_KEY: string; VITE_APP_CLIENT_ID: string; - VITE_APP_WEBSOCKET: string; - VITE_APP_SSE: string; + VITE_APP_MESSAGE_ENABLED: string; + VITE_APP_MESSAGE_TRANSPORT: string; + VITE_APP_MESSAGE_PATH: string; } interface ImportMeta { readonly env: ImportMetaEnv; diff --git a/src/utils/push.ts b/src/utils/push.ts new file mode 100644 index 0000000..f091b6c --- /dev/null +++ b/src/utils/push.ts @@ -0,0 +1,113 @@ +import { getToken } from '@/utils/auth'; +import { ElNotification } from 'element-plus'; +import { useNoticeStore } from '@/store/modules/notice'; +import { parsePushMessage, PUSH_MESSAGE_TYPE, shouldAppendNotice } from '@/utils/push-message'; + +let closePushConnection: (() => void) | undefined; + +const appendNotice = (raw: string) => { + const payload = parsePushMessage(raw); + if (!shouldAppendNotice(payload)) { + return; + } + useNoticeStore().addNotice({ + title: payload.type === PUSH_MESSAGE_TYPE.NOTICE ? '通知公告' : '系统消息', + type: payload.type, + source: payload.source, + message: payload.message ?? '', + content: payload.data?.noticeContent, + data: payload.data, + path: payload.path, + query: payload.query, + read: false, + time: new Date(payload.timestamp ?? Date.now()).toLocaleString() + }); + ElNotification({ + title: payload.type === PUSH_MESSAGE_TYPE.NOTICE ? '通知公告' : '消息', + message: payload.message ?? '', + type: 'success', + duration: 3000 + }); +}; + +const buildSseUrl = (path: string) => { + return `${import.meta.env.VITE_APP_BASE_API}${path}?Authorization=Bearer ${getToken()}&clientid=${import.meta.env.VITE_APP_CLIENT_ID}`; +}; + +const buildWsUrl = (path: string) => { + const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; + return `${protocol}${window.location.host}${buildSseUrl(path)}`; +}; + +const initSsePush = (url: string) => { + const { data, error, close } = useEventSource(url, [], { + autoReconnect: { + retries: 5, + delay: 5000, + onFailed() { + console.log('Failed to connect after 5 retries'); + } + } + }); + closePushConnection = close; + + watch(error, () => { + console.log('SSE connection error:', error.value); + error.value = null; + }); + + watch(data, () => { + if (!data.value) return; + appendNotice(data.value); + data.value = null; + }); +}; + +const initWsPush = (url: string) => { + const { close } = useWebSocket(url, { + autoReconnect: { + retries: 3, + delay: 1000, + onFailed() { + console.log('websocket重连失败'); + } + }, + heartbeat: { + message: 'ping', + interval: 10000, + pongTimeout: 2000 + }, + onConnected() { + console.log('websocket已经连接'); + }, + onDisconnected() { + console.log('websocket已经断开'); + }, + onMessage: (_, e) => { + if (String(e.data) === 'pong') { + return; + } + appendNotice(String(e.data)); + } + }); + closePushConnection = close; +}; + +export const initPush = () => { + closePush(); + if (import.meta.env.VITE_APP_MESSAGE_ENABLED === 'false') { + return; + } + const path = import.meta.env.VITE_APP_MESSAGE_PATH || '/resource/message'; + const transport = import.meta.env.VITE_APP_MESSAGE_TRANSPORT || 'sse'; + if (transport.toLowerCase() === 'websocket') { + initWsPush(buildWsUrl(path)); + return; + } + initSsePush(buildSseUrl(path)); +}; + +export const closePush = () => { + closePushConnection?.(); + closePushConnection = undefined; +}; diff --git a/src/utils/sse.ts b/src/utils/sse.ts deleted file mode 100644 index c3abd78..0000000 --- a/src/utils/sse.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { getToken } from '@/utils/auth'; -import { ElNotification } from 'element-plus'; -import { useNoticeStore } from '@/store/modules/notice'; -import { parsePushMessage, PUSH_MESSAGE_TYPE, shouldAppendNotice } from '@/utils/push-message'; - -// 初始化 -export const initSSE = (url: any) => { - if (import.meta.env.VITE_APP_SSE === 'false') { - return; - } - - url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID; - const { data, error } = useEventSource(url, [], { - autoReconnect: { - retries: 5, - delay: 5000, - onFailed() { - console.log('Failed to connect after 5 retries'); - } - } - }); - - watch(error, () => { - console.log('SSE connection error:', error.value); - error.value = null; - }); - - watch(data, () => { - if (!data.value) return; - const payload = parsePushMessage(data.value); - if (shouldAppendNotice(payload)) { - useNoticeStore().addNotice({ - title: payload.type === PUSH_MESSAGE_TYPE.NOTICE ? '通知公告' : '系统消息', - type: payload.type, - source: payload.source, - message: payload.message ?? '', - content: payload.data?.noticeContent, - data: payload.data, - path: payload.path, - query: payload.query, - read: false, - time: new Date(payload.timestamp ?? Date.now()).toLocaleString() - }); - ElNotification({ - title: payload.type === PUSH_MESSAGE_TYPE.NOTICE ? '通知公告' : '消息', - message: payload.message ?? '', - type: 'success', - duration: 3000 - }); - } - data.value = null; - }); -}; diff --git a/src/utils/websocket.ts b/src/utils/websocket.ts deleted file mode 100644 index a9cf2c8..0000000 --- a/src/utils/websocket.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { getToken } from '@/utils/auth'; -import { ElNotification } from 'element-plus'; -import { useNoticeStore } from '@/store/modules/notice'; -import { parsePushMessage, PUSH_MESSAGE_TYPE, shouldAppendNotice } from '@/utils/push-message'; - -// 初始化socket -export const initWebSocket = (url: any) => { - if (import.meta.env.VITE_APP_WEBSOCKET === 'false') { - return; - } - url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID; - useWebSocket(url, { - autoReconnect: { - // 重连最大次数 - retries: 3, - // 重连间隔 - delay: 1000, - onFailed() { - console.log('websocket重连失败'); - } - }, - heartbeat: { - message: JSON.stringify({ type: 'ping' }), - // 发送心跳的间隔 - interval: 10000, - // 接收到心跳response的超时时间 - pongTimeout: 2000 - }, - onConnected() { - console.log('websocket已经连接'); - }, - onDisconnected() { - console.log('websocket已经断开'); - }, - onMessage: (_, e) => { - if (typeof e.data === 'string' && e.data.includes('ping')) { - return; - } - const payload = parsePushMessage(String(e.data)); - if (shouldAppendNotice(payload)) { - useNoticeStore().addNotice({ - title: payload.type === PUSH_MESSAGE_TYPE.NOTICE ? '通知公告' : '系统消息', - type: payload.type, - source: payload.source, - message: payload.message ?? '', - content: payload.data?.noticeContent, - data: payload.data, - path: payload.path, - query: payload.query, - read: false, - time: new Date(payload.timestamp ?? Date.now()).toLocaleString() - }); - ElNotification({ - title: payload.type === PUSH_MESSAGE_TYPE.NOTICE ? '通知公告' : '消息', - message: payload.message ?? '', - type: 'success', - duration: 3000 - }); - } - } - }); -};