feat: ws 封装工具测试

This commit is contained in:
TsMask
2024-01-25 11:06:39 +08:00
parent 4572c2060d
commit 9eaaba2d0a
3 changed files with 118 additions and 38 deletions

View File

@@ -1,13 +1,19 @@
import { sessionGet } from "@/utils/cache-session-utils";
import { sessionGet } from '@/utils/cache-session-utils';
import { getToken } from './auth-token';
import { localGet } from '@/utils/cache-local-utils';
import { CACHE_LOCAL_I18N } from '@/constants/cache-keys-constants';
import { TOKEN_RESPONSE_FIELD } from '@/constants/token-constants';
/**连接参数类型 */
export type TypeParams = {
export type OptionsType = {
/**WebSocket服务器将响应的URL */
url?: string;
/**地址栏参数 */
params?: Record<string, string | number | boolean | undefined>;
/**onopen事件的回调函数 */
onopen?: Function;
/**message事件的回调函数 */
onmessage: Function;
onmessage: (data: Record<string, any>) => void;
/**error事件的回调函数 */
onerror: Function;
/**close事件的回调函数 */
@@ -41,7 +47,7 @@ export class WS {
/**ws 实例 */
private ws: WebSocket | null = null;
/**ws 连接参数 */
private params: TypeParams | null = null;
private options: OptionsType | null = null;
/**心跳调度器 */
private heartInterval: number = 0;
/**重连定时器 */
@@ -51,87 +57,135 @@ export class WS {
* 构造函数
* @param {object} params 构造函数参数
*/
constructor(params: TypeParams) {
constructor(options: OptionsType) {
if (!window.WebSocket) {
// 检测浏览器支持
console.error('抱歉! 浏览器不支持websocket');
return;
}
this.params = params;
this.create(params);
this.options = options;
this.create(options);
}
/**
* 创建链接
* @param {object} params 连接参数
* @param {object} options 连接参数
*/
public create(params: TypeParams) {
public create(options: OptionsType) {
try {
if (!params.url) {
if (!options.url) {
// 兼容旧前端可改配置文件
const baseUrl = import.meta.env.PROD
const wsUrl = import.meta.env.PROD
? sessionGet('wsUrl') || import.meta.env.VITE_API_BASE_URL
: import.meta.env.VITE_API_BASE_URL;
params.url = `ws://${baseUrl}/ws`;
: '/socket';
if (wsUrl.startsWith('ws')) {
options.url = `${wsUrl}/ws`;
} else if (wsUrl.startsWith('https')) {
options.url = `${wsUrl.replace('https', 'wss')}/ws`;
} else if (wsUrl.startsWith('http')) {
options.url = `${wsUrl.replace('http', 'ws')}/ws`;
} else {
const protocol =
window.location.protocol === 'https:' ? 'wss://' : 'ws://';
options.url = `${protocol}${location.host}${wsUrl}/ws`;
}
const ws = new WebSocket(params.url);
// 地址栏参数
let params = options.params || {};
// 设置 token
const token = getToken();
if (token) {
params[TOKEN_RESPONSE_FIELD] = token;
}
// 多语言处理
params['language'] = localGet(CACHE_LOCAL_I18N) || 'en_US';
let paramStr = '';
for (const key in params) {
const value = params[key];
// 空字符或未定义的值不作为参数发送
if (value === '' || value === undefined) continue;
paramStr += `&${encodeURIComponent(key)}=${encodeURIComponent(
value
)}`;
}
if (paramStr && paramStr.startsWith('&')) {
options.url = `${options.url}?${paramStr.substring(1)}`;
}
}
const ws = new WebSocket(options.url, 'omc-ws');
// 用于指定连接成功后的回调函数。
ws.onopen = ev => {
if (params.heartTimer && params.heartTimer > 0) {
this.heartCheck(params.heartTimer);
if (options.heartTimer && options.heartTimer > 0) {
this.heartCheck(options.heartTimer);
}
if (typeof params.onopen === 'function') {
params.onopen(ev);
if (typeof options.onopen === 'function') {
options.onopen(ev);
}
};
// 用于指定当从服务器接受到信息时的回调函数。
ws.onmessage = ev => {
if (typeof params.onmessage === 'function') {
params.onmessage(ev);
const data = ev.data;
// 解析文本消息
if (ev.type === 'message') {
try {
const jsonData = JSON.parse(data);
if (typeof options.onmessage === 'function') {
options.onmessage(jsonData);
}
} catch (error) {
console.error('websocket 消息格式错误', error);
}
}
};
// 用于指定连接关闭后的回调函数。
ws.onclose = ev => {
if (typeof params.onclose === 'function') {
params.onclose(ev);
if (typeof options.onclose === 'function') {
options.onclose(ev);
}
};
// 用于指定连接失败后的回调函数。
ws.onerror = ev => {
console.error('websocket 连接异常', ev);
if (typeof params.onerror === 'function') {
params.onerror(ev);
if (typeof options.onerror === 'function') {
options.onerror(ev);
}
if (params.reconnectTimer && params.reconnectTimer > 0) {
this.reconnect(params.reconnectTimer);
if (options.reconnectTimer && options.reconnectTimer > 0) {
this.reconnect(options.reconnectTimer);
}
};
this.ws = ws;
} catch (error) {
if (typeof params.onerror === 'function') {
params.onerror(error);
if (typeof options.onerror === 'function') {
options.onerror(error);
}
if (params.reconnectTimer && params.reconnectTimer > 0) {
this.reconnect(params.reconnectTimer);
if (options.reconnectTimer && options.reconnectTimer > 0) {
this.reconnect(options.reconnectTimer);
}
}
}
// 发送消息
send(data: Record<string, any>) {
public send(data: Record<string, any>) {
if (!this.ws) {
console.warn('websocket 不可用');
return;
}
console.log(' readyState', this.ws.readyState);
if (
this.ws.readyState === WebSocket.CLOSED ||
this.ws.readyState === WebSocket.CLOSING
) {
this.close();
return;
}
this.ws.send(JSON.stringify(data));
}
// 手动关闭socket
close() {
public close() {
this.heartInterval && clearInterval(this.heartInterval);
this.reconnectTimeout && clearTimeout(this.reconnectTimeout);
if (!this.ws) {
@@ -142,7 +196,7 @@ export class WS {
}
// 周期性发送ping 保活
heartCheck(heartTimer: number) {
private heartCheck(heartTimer: number) {
this.heartInterval = window.setInterval(() => {
this.send({
type: 'ping',
@@ -151,12 +205,12 @@ export class WS {
}
// 断线重连
reconnect(reconnectTimer: number) {
private reconnect(reconnectTimer: number) {
if (this.reconnectTimeout > 0) return;
clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = window.setTimeout(() => {
if (this.params) {
this.create(this.params);
if (this.options) {
this.create(this.options);
this.reconnectTimeout = 0;
}
}, reconnectTimer);

View File

@@ -13,10 +13,29 @@ import { ColumnsType } from 'ant-design-vue/lib/table/Table';
import { message } from 'ant-design-vue/lib';
import { hasPermissions } from '@/plugins/auth-user';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { WS, OptionsType } from '@/plugins/ws-websocket';
import useI18n from '@/hooks/useI18n';
const { t } = useI18n();
onMounted(() => {});
onMounted(() => {
const options: OptionsType = {
params: {
subGroupID: '1005',
},
onmessage: ev => {
// 接收数据后回调
console.log(ev);
},
onerror: (ev: any) => {
// 接收数据后回调
console.log(ev);
},
// 保活周期 10s
heartTimer: 0,
// 断线重连
reconnectTimer: 0,
};
const ws = new WS(options);
});
</script>
<template>

View File

@@ -25,6 +25,13 @@ export default defineConfig(({ mode }) => {
changeOrigin: true,
rewrite: p => p.replace(env.VITE_API_BASE_URL, ''),
},
// 代理 websockets
'/socket': {
target: 'ws://192.168.5.58:3040',
changeOrigin: true,
rewrite: p => p.replace('/socket', ''),
ws: true,
},
},
},
resolve: {