UniApp 在 APP 端如何使用 WebSocket以及常见问题
一、WebSocket 基础概念
WebSocket 是一种在单个TCP连接上进行全双工通信的协议,适用于实时数据传输场景(如聊天室、实时游戏、股票行情等)。
与传统HTTP对比
特性 | WebSocket | HTTP |
---|---|---|
连接方式 | 长连接 | 短连接 |
通信方向 | 全双工 | 半双工 |
数据格式 | 二进制/文本 | 文本 |
首部大小 | 2-10字节 | 8000+字节 |
二、UniApp 中使用 WebSocket
1. API 概览
UniApp 封装了微信小程序风格的 WebSocket API:
uni.connectSocket()
- 创建连接uni.onSocketOpen()
- 监听连接打开uni.onSocketError()
- 监听错误uni.sendSocketMessage()
- 发送消息uni.onSocketMessage()
- 接收消息uni.closeSocket()
- 关闭连接uni.onSocketClose()
- 监听关闭
2. 完整使用示例
// websocket.js
let socketTask = null;
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;
export function connectWebSocket() {
return new Promise((resolve, reject) => {
const url = 'wss://your-websocket-server.com';
// 创建连接
socketTask = uni.connectSocket({
url: url,
success: () => {
console.log('WebSocket 连接创建中...');
},
fail: (err) => {
console.error('连接创建失败:', err);
reject(err);
}
});
// 监听打开事件
socketTask.onOpen((res) => {
console.log('WebSocket 连接已打开');
reconnectAttempts = 0;
resolve(socketTask);
});
// 监听错误事件
socketTask.onError((err) => {
console.error('WebSocket 错误:', err);
handleReconnection();
reject(err);
});
// 监听关闭事件
socketTask.onClose((res) => {
console.log('WebSocket 连接已关闭', res);
if (!res.code === 1000) { // 非正常关闭
handleReconnection();
}
});
});
}
function handleReconnection() {
if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++;
const delay = Math.min(1000 * reconnectAttempts, 5000);
console.log(`尝试第 ${reconnectAttempts} 次重连,${delay}ms后执行`);
setTimeout(() => {
connectWebSocket().catch(console.error);
}, delay);
} else {
console.error(`已达到最大重连次数 ${maxReconnectAttempts}`);
}
}
// 发送消息
export function sendWebSocketMessage(message) {
return new Promise((resolve, reject) => {
if (!socketTask || socketTask.readyState !== 1) {
reject('WebSocket 未连接');
return;
}
socketTask.send({
data: JSON.stringify(message),
success: () => resolve(),
fail: (err) => reject(err)
});
});
}
// 关闭连接
export function closeWebSocket() {
if (socketTask) {
socketTask.close({
code: 1000,
reason: '用户主动关闭'
});
}
}
3. 心跳机制实现
let heartbeatTimer = null;
function startHeartbeat() {
// 每30秒发送一次心跳
heartbeatTimer = setInterval(() => {
sendWebSocketMessage({
type: 'heartbeat',
timestamp: Date.now()
}).catch(() => {
clearInterval(heartbeatTimer);
});
}, 30000);
}
// 在onOpen中调用
socketTask.onOpen(() => {
startHeartbeat();
});
// 在onClose中清除
socketTask.onClose(() => {
clearInterval(heartbeatTimer);
});
4. 消息队列处理
当网络不稳定时,可实现消息队列:
let messageQueue = [];
let isSending = false;
async function processQueue() {
if (isSending || messageQueue.length === 0) return;
isSending = true;
const message = messageQueue.shift();
try {
await sendWebSocketMessage(message);
} catch (err) {
messageQueue.unshift(message); // 重新放回队列
} finally {
isSending = false;
processQueue();
}
}
export function queueMessage(message) {
messageQueue.push(message);
processQueue();
}
三、注意事项
平台差异:
- iOS 对后台WebSocket连接限制严格
- 部分安卓机型可能在锁屏后断开连接
安全要求:
- 必须使用
wss
协议(SSL加密) - 建议实现消息加密(如AES)
- 必须使用
性能优化:
- 大数据量传输建议使用ArrayBuffer
- 避免频繁发送小消息(可合并发送)
调试技巧:
// 开启调试模式 uni.setEnableDebug({ enableDebug: true });
四、完整页面示例
<template>
<view class="container">
<button @click="connect">连接WebSocket</button>
<button @click="send">发送测试消息</button>
<button @click="close">关闭连接</button>
<scroll-view scroll-y class="message-box">
<view v-for="(msg, index) in messages" :key="index">
{{ msg }}
</view>
</scroll-view>
</view>
</template>
<script>
import { connectWebSocket, sendWebSocketMessage, closeWebSocket } from '@/utils/websocket';
export default {
data() {
return {
messages: [],
socketTask: null
}
},
onUnload() {
closeWebSocket();
},
methods: {
async connect() {
try {
this.socketTask = await connectWebSocket();
this.socketTask.onMessage((res) => {
this.messages.push('收到消息: ' + res.data);
});
this.messages.push('WebSocket 已连接');
} catch (err) {
this.messages.push('连接失败: ' + err);
}
},
async send() {
try {
await sendWebSocketMessage({
type: 'test',
content: 'Hello WebSocket',
timestamp: Date.now()
});
this.messages.push('消息已发送');
} catch (err) {
this.messages.push('发送失败: ' + err);
}
},
close() {
closeWebSocket();
this.messages.push('已主动关闭连接');
}
}
}
</script>
<style>
.container {
padding: 20px;
}
.message-box {
height: 300px;
margin-top: 20px;
border: 1px solid #eee;
padding: 10px;
}
</style>
五、常见问题解决
Q1: 安卓设备连接不稳定
解决方案:在manifest.json中配置:
"app-plus": { "keepRunning": true, "optimization": { "keepAlive": true } }
Q2: iOS后台断连
解决方案:启用后台模式(需在manifest.json中声明):
"ios": { "UIBackgroundModes": ["audio"] }
并通过心跳保持活跃
Q3: 真机调试无法连接
- 检查项:
- 是否使用HTTPS/WSS
- 域名是否加入白名单
- 手机网络是否正常
Q4: 如何发送二进制数据
// 发送ArrayBuffer
const buffer = new ArrayBuffer(8);
socketTask.send({
data: buffer,
fail: console.error
});