前言
在当今互联网应用中,实时通信已经成为一个标配功能,特别是对于需要即时响应的场景,如在线客服、咨询系统等。本文将分享如何在小程序中实现一个高效稳定的WebSocket连接,以及如何处理断线重连、消息发送与接收等常见问题。
WebSocket简介
WebSocket是HTML5提供的一种在单个TCP连接上进行全双工通讯的协议。相比传统的HTTP请求,WebSocket具有以下优势:
- 持久连接:一次握手,持续通信,避免了HTTP的重复连接
- 低延迟:全双工通信,服务端可以主动推送数据
- 较小的数据包开销:相比HTTP请求的头信息,WebSocket的数据包头较小
在小程序中实现WebSocket连接
小程序提供了uni.connectSocket
等API来支持WebSocket连接。以下是一个完整实现的代码示例:
javascript
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实现必须考虑断线重连机制。以下是一个简单而高效的重连实现:
javascript
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连接:
javascript
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();
}
}
心跳机制
为了保持连接活跃并检测连接状态,实现心跳机制是必要的:
javascript
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();
}
}
发送消息
当用户发送消息时,需要检查连接状态并正确格式化消息:
javascript
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连接后加载历史消息:
javascript
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实现需要考虑各种边缘情况,包括网络波动、设备切换、应用切换等场景。通过合理的重连策略和状态管理,我们可以为用户提供流畅的实时通信体验。