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
});