1、配置文件
export default {
serverUrl: `ws://127.0.0.1/socket`,
backupServerUrl: '',
connectTimeout: 10000,
reconnect: {
maxAttempts: 10,
initialDelay: 3000,
exponentialBackoff: true
}
heartbeat: {
clientInterval: 30000,
serverTimeout: 40000
}
}
2、wesocket.js文件
import wsConfig from './ws-config.js';
const cleanServerAddress = () => {
try {
let serverAddress = JSON.parse(uni.getStorageSync('serverAddress'))
if (serverAddress.includes('http://')) {
return serverAddress.replace('http://', '');
} else if (serverAddress.includes('https://')) {
return serverAddress.replace('https://', '');
}
return serverAddress;
} catch (error) {
console.error('获取服务器地址失败:', error);
return '/api/v1';
}
};
let ws = null;
let wsState = 'CLOSED';
let currentServerUrl = wsConfig.serverUrl;
let reconnectTimer = null;
let reconnectCount = 0;
let heartbeatTimer = null;
let serverHeartbeatTimer = null;
let messageCallback = null;
export const setMessageCallback = (callback) => {
if (typeof callback === 'function') {
messageCallback = callback;
}
};
export const initWebSocket = () => {
ws = uni.connectSocket({
url: currentServerUrl,
header: {
'content-type': 'application/json'
},
protocols: ['protocol1'],
complete: () => { }
});
ws.onOpen((res) => {
wsState = 'OPEN';
reconnectCount = 0;
if (messageCallback) {
try {
messageCallback({ type: 'connected', data: res });
} catch (error) {
console.error('WebSocket连接打开回调错误:', error);
}
}
startClientHeartbeat();
});
ws.onClose((res) => {
wsState = 'CLOSED';
if (messageCallback) {
try {
messageCallback({ type: 'disconnected', data: res });
} catch (error) {
console.error('WebSocket连接关闭回调错误:', error);
}
}
stopClientHeartbeat();
stopServerHeartbeatCheck();
if (reconnectCount < wsConfig.reconnect.maxAttempts) {
startReconnect();
} else {
if (messageCallback) {
try {
messageCallback({
type: 'reconnect_failed',
data: { attempts: wsConfig.reconnect.maxAttempts }
});
} catch (error) {
console.error('WebSocket重连失败回调错误:', error);
}
}
}
});
ws.onError((err) => {
console.error('WebSocket连接错误:', err);
wsState = 'ERROR';
if (messageCallback) {
try {
messageCallback({ type: 'error', data: err });
} catch (error) {
console.error('WebSocket错误回调错误:', error);
}
}
closeWebSocket();
});
ws.onMessage((res) => {
try {
const message = JSON.parse(res.data);
if (message.type === 'server_hb') {
resetServerHeartbeatCheck();
}
else if (message.type === 'device_status_change') {
if (messageCallback) {
try {
messageCallback({ type: 'message', data: message });
} catch (error) {
console.error('WebSocket消息回调错误:', error);
}
}
sendMessage({
type: 'ack',
data: {
messageId: message.messageId
}
});
}
else {
if (messageCallback) {
try {
messageCallback({ type: 'message', data: message });
} catch (error) {
console.error('WebSocket消息回调错误:', error);
}
}
}
} catch (error) {
console.error('WebSocket消息解析错误:', error);
if (messageCallback) {
try {
messageCallback({
type: 'parse_error',
data: {
originalData: res.data,
error: error.message
}
});
} catch (callbackError) {
console.error('WebSocket解析错误回调错误:', callbackError);
}
}
}
});
};
export const sendMessage = (message) => {
if (!ws || wsState !== 'OPEN') {
return false;
}
const data = typeof message === 'string' ? message : JSON.stringify(message);
ws.send({
data: data,
success: (res) => { },
fail: (err) => {
console.error('WebSocket消息发送失败:', err);
if (messageCallback) {
try {
messageCallback({
type: 'send_error',
data: { message, error: err }
});
} catch (error) {
console.error('WebSocket发送错误回调错误:', error);
}
}
}
});
return true;
};
export const closeWebSocket = () => {
if (ws) {
ws.close({
success: (res) => {
console.log('WebSocket连接已成功关闭:', res);
},
fail: (err) => {
console.error('WebSocket关闭失败:', err);
}
});
ws = null;
wsState = 'CLOSED';
}
};
const getReconnectDelay = () => {
if (wsConfig.reconnect.exponentialBackoff) {
return Math.min(wsConfig.reconnect.initialDelay * Math.pow(2, reconnectCount - 1), 10000);
} else {
return wsConfig.reconnect.initialDelay;
}
};
const startReconnect = () => {
reconnectCount++;
const delay = getReconnectDelay();
console.log(`WebSocket重连尝试 ${reconnectCount}/${wsConfig.reconnect.maxAttempts},延迟 ${delay}ms`);
reconnectTimer = setTimeout(() => {
initWebSocket();
}, delay);
};
const startClientHeartbeat = () => {
stopClientHeartbeat();
heartbeatTimer = setInterval(() => {
if (ws && wsState === 'OPEN') {
sendMessage({
type: 'client_hb',
timestamp: Date.now()
});
startServerHeartbeatCheck();
}
}, wsConfig.heartbeat.clientInterval);
};
const stopClientHeartbeat = () => {
if (heartbeatTimer) {
clearInterval(heartbeatTimer);
heartbeatTimer = null;
}
};
const startServerHeartbeatCheck = () => {
stopServerHeartbeatCheck();
serverHeartbeatTimer = setTimeout(() => {
console.error('WebSocket服务端心跳超时,断开连接');
if (messageCallback) {
try {
messageCallback({
type: 'heartbeat_timeout',
data: { timeout: wsConfig.heartbeat.serverTimeout }
});
} catch (error) {
console.error('WebSocket心跳超时回调错误:', error);
}
}
closeWebSocket();
}, wsConfig.heartbeat.serverTimeout);
};
const resetServerHeartbeatCheck = () => {
startServerHeartbeatCheck();
};
const stopServerHeartbeatCheck = () => {
if (serverHeartbeatTimer) {
clearTimeout(serverHeartbeatTimer);
serverHeartbeatTimer = null;
}
};
export const getWebSocketState = () => {
return wsState;
};
export default {
initWebSocket,
sendMessage,
closeWebSocket,
setMessageCallback,
getWebSocketState
};
3、页面中使用
import wsManager from "@/api/websocket";
onLaunch(() => {
wsManager.initWebSocket();
});
onShow(() => {
const wsState = wsManager.getWebSocketState();
if (wsState === "CLOSED") {
wsManager.initWebSocket();
}
});
onLoad(() => {
const wsState = wsManager.getWebSocketState();
if (wsState === "CLOSED") {
wsManager.initWebSocket();
}
wsManager.setMessageCallback(handleWebSocketMessage);
});
const handleWebSocketMessage = ({ type, data }) => {
switch (type) {
case "connected":
"WebSocket已连接";
break;
case "disconnected":
"WebSocket连接断开";
break;
case "error":
"WebSocket连接错误";
break;
case "message":
"WebSocket已连接 收到消息: " + data.message;
break;
case "reconnect_failed":
"WebSocket重连失败";
break;
case "heartbeat_timeout":
"WebSocket心跳超时";
break;
default:
}
};