前言
在當今互聯網應用中,實時通信已經成為一個標配功能,特別是對于需要即時響應的場景,如在線客服、咨詢系統等。本文將分享如何在小程序中實現一個高效穩定的WebSocket連接,以及如何處理斷線重連、消息發送與接收等常見問題。
WebSocket簡介
WebSocket是HTML5提供的一種在單個TCP連接上進行全雙工通訊的協議。相比傳統的HTTP請求,WebSocket具有以下優勢:
- 持久連接:一次握手,持續通信,避免了HTTP的重復連接
- 低延遲:全雙工通信,服務端可以主動推送數據
- 較小的數據包開銷:相比HTTP請求的頭信息,WebSocket的數據包頭較小
在小程序中實現WebSocket連接
小程序提供了uni.connectSocket
等API來支持WebSocket連接。以下是一個完整實現的代碼示例:
initSocket() {try {if (!this.token) { return; }uni.connectSocket({ url: 'ws://example-domain.com:8000?token=' + this.token });uni.onSocketOpen(() => { console.log('WebSocket 已連接'); this.socketActive = true; this.reconnectCount = 0; });uni.onSocketMessage((res) => {// 處理接收到的消息try {// 嘗試解析JSON格式的消息const msgData = JSON.parse(res.data);// 判斷消息類型if (msgData.type === 'msg') {// 如果是消息類型,提取content內容并顯示const messageText = msgData.content || '';if (messageText) {this.messages.push({from: 'other',text: messageText,time: this.formatTime(new Date())});this.$nextTick(() => { this.toBottom(); });}} else {// 其他類型的消息console.log('收到非消息類型的數據:', msgData);}} catch (e) {// 如果不是JSON格式,直接顯示原始文本console.log('消息不是JSON格式,直接顯示:', res.data);this.messages.push({from: 'other',text: res.data,time: this.formatTime(new Date())});this.$nextTick(() => { this.toBottom(); });}});uni.onSocketError((err) => { console.error('WebSocket 錯誤', err); this.socketActive = false; this.tryReconnect(); });uni.onSocketClose(() => { console.log('WebSocket 已關閉'); this.socketActive = false; this.tryReconnect(); });} catch (e) { console.error('WebSocket 創建失敗', e); }
}
斷線重連機制
一個穩定的WebSocket實現必須考慮斷線重連機制。以下是一個簡單而高效的重連實現:
tryReconnect() {if (!this.token) return;if (!this.isPageVisible) return;if (this.reconnectCount >= this.maxReconnect) return;if (this.reconnectTimer) return; // 已經計劃了重連this.reconnectCount++;this.reconnectTimer = setTimeout(() => {this.reconnectTimer = null;console.log('嘗試重連 WebSocket, 第' + this.reconnectCount + '次');this.initSocket();}, 3000); // 3秒后嘗試重連
}closeSocket() {if (this.reconnectTimer) {clearTimeout(this.reconnectTimer);this.reconnectTimer = null;}if (this.socketActive) {console.log('主動斷開WebSocket連接');uni.closeSocket();this.socketActive = false;}
}
處理頁面生命周期
在小程序中,我們需要在適當的頁面生命周期中管理WebSocket連接:
onLoad() {this.isPageVisible = true;this.token = wx.getStorageSync('token') || '';if (this.token) {this.initSocket();// 定期發送心跳包setTimeout(() => {this.ping();}, 30000);}// 其他初始化代碼...
}onUnload() {this.closeSocket();this.isPageVisible = false;
}onHide() {// 頁面隱藏時斷開連接this.closeSocket();this.isPageVisible = false;
}onShow() {// 頁面顯示時重新連接this.isPageVisible = true;if (this.token && !this.socketActive) {this.initSocket();}
}
心跳機制
為了保持連接活躍并檢測連接狀態,實現心跳機制是必要的:
ping() {if (!this.token) {return;}if (!this.isPageVisible) {return;}// 發送心跳包if (this.socketActive) {uni.sendSocketMessage({ data: `{"type":"ping"}` });} else {this.messages.push({from: 'other',text: '連接已斷開,正在重連...',time: this.formatTime(new Date())});this.tryReconnect();}
}
發送消息
當用戶發送消息時,需要檢查連接狀態并正確格式化消息:
send() {const txt = this.newMsg.trim();if (!txt) return;if (!this.token) {uni.navigateTo({ url: '/pages/login/login' });return;}// 添加消息到本地列表this.messages.push({from: 'me',text: txt,time: this.formatTime(new Date())});this.newMsg = '';// 發送到服務器if (this.socketActive) {uni.sendSocketMessage({ data: `{"type":"msg","content":"${txt}"}` });} else {this.messages.push({from: 'other',text: '連接已斷開,正在重連...',time: this.formatTime(new Date())});this.tryReconnect();}
}
加載歷史消息
為了提供更好的用戶體驗,我們可以在建立WebSocket連接后加載歷史消息:
async loadHistoryMessages() {try {const res = await this.$axios("api/historyMessages", { limit: 100 });if (res.data.code == 0) {// 處理歷史消息數據const historyData = res.data.lists || [];// 處理邏輯...}} catch (e) {console.error("加載歷史記錄失敗", e);}
}
優化用戶體驗的技巧
- 消息發送狀態:可以為每條消息添加狀態標記,如"發送中"、“已發送”、“發送失敗”
- 消息隊列:當連接斷開時,可以將消息加入隊列,連接恢復后再發送
- 漸進式加載:歷史消息可以分頁加載,以提高初始加載速度
- 消息格式化:支持不同類型的消息格式,如文本、圖片、鏈接等
- 連接狀態提示:在UI上顯示當前連接狀態,讓用戶了解實時情況
總結
在小程序中實現WebSocket可以大大提升實時通信體驗。本文介紹了WebSocket的基本實現、斷線重連、心跳機制等關鍵技術點。希望這些經驗能幫助你在自己的項目中構建更穩定、高效的實時通信功能。
記住,一個健壯的WebSocket實現需要考慮各種邊緣情況,包括網絡波動、設備切換、應用切換等場景。通過合理的重連策略和狀態管理,我們可以為用戶提供流暢的實時通信體驗。