小程序WebSocket实践(心跳检测、断线重连)

我把小程序WebSocket的一些功能封装成一个类,里面包括建立连接、监听消息、发送消息、心跳检测、断线重连等等常用的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
export default class websocket {
constructor({ heartCheck, isReconnection }) {
// 是否连接
this._isLogin = false;
// 当前网络状态
this._netWork = true;
// 是否人为退出
this._isClosed = false;
// 心跳检测频率
this._timeout = 3000;
this._timeoutObj = null;
// 当前重连次数
this._connectNum = 0;
// 心跳检测和断线重连开关,true为启用,false为关闭
this._heartCheck = heartCheck;
this._isReconnection = isReconnection;
this._onSocketOpened();
}
// 心跳重置
_reset() {
clearTimeout(this._timeoutObj);
return this;
}
// 心跳开始
_start() {
let _this = this;
this._timeoutObj = setInterval(() => {
wx.sendSocketMessage({
// 心跳发送的信息应由前后端商量后决定
data: JSON.stringify({
"key": 'value'
}),
success(res) {
console.log(res)
console.log("发送心跳成功");
},
fail(err) {
console.log(err)
_this._reset()
}
});
}, this._timeout);
}
// 监听websocket连接关闭
onSocketClosed(options) {
wx.onSocketClose(err => {
console.log('当前websocket连接已关闭,错误信息为:' + JSON.stringify(err));
// 停止心跳连接
if (this._heartCheck) {
this._reset();
}
// 关闭已登录开关
this._isLogin = false;
// 检测是否是用户自己退出小程序
if (!this._isClosed) {
// 进行重连
if (this._isReconnection) {
this._reConnect(options)
}
}

})
}
// 检测网络变化
onNetworkChange(options) {
wx.onNetworkStatusChange(res => {
console.log('当前网络状态:' + res.isConnected);
if (!this._netWork) {
this._isLogin = false;
// 进行重连
if (this._isReconnection) {
this._reConnect(options)
}
}
})
}
_onSocketOpened() {
wx.onSocketOpen(res => {
console.log('websocket已打开');
// 打开已登录开关
this._isLogin = true;
// 发送心跳
if (this._heartCheck) {
this._reset()._start();
}
// 发送登录信息
wx.sendSocketMessage({
// 这里是第一次建立连接所发送的信息,应由前后端商量后决定
data: JSON.stringify({
"key": 'value'
})
})
// 打开网络开关
this._netWork = true;
})
}
// 接收服务器返回的消息
onReceivedMsg(callBack) {
wx.onSocketMessage(msg => {
if (typeof callBack == "function") {
callBack(msg)
} else {
console.log('参数的类型必须为函数')
}
})
}

// 建立websocket连接
initWebSocket(options) {
let _this = this;
if (this._isLogin) {
console.log("您已经登录了");
} else {
// 检查网络
wx.getNetworkType({
success(result) {
if (result.networkType != 'none') {
// 开始建立连接
wx.connectSocket({
url: options.url,
success(res) {
if (typeof options.success == "function") {
options.success(res)
} else {
console.log('参数的类型必须为函数')
}
},
fail(err) {
if (typeof options.fail == "function") {
options.fail(err)
} else {
console.log('参数的类型必须为函数')
}
}
})
} else {
console.log('网络已断开');
_this._netWork = false;
// 网络断开后显示model
wx.showModal({
title: '网络错误',
content: '请重新打开网络',
showCancel: false,
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
}
}
})
}
}
})
}
}
// 发送websocket消息
sendWebSocketMsg(options) {
wx.sendSocketMessage({
data: options.data,
success(res) {
if (typeof options.success == "function") {
options.success(res)
} else {
console.log('参数的类型必须为函数')
}
},
fail(err) {
if (typeof options.fail == "function") {
options.fail(err)
} else {
console.log('参数的类型必须为函数')
}
}
})
}
// 重连方法,会根据时间频率越来越慢
_reConnect(options) {
let timer, _this = this;
if (this._connectNum < 20) {
timer = setTimeout(() => {
this.initWebSocket(options)
}, 3000)
this._connectNum += 1;
} else if (this._connectNum < 50) {
timer = setTimeout(() => {
this.initWebSocket(options)
}, 10000)
this._connectNum += 1;
} else {
timer = setTimeout(() => {
this.initWebSocket(options)
}, 450000)
this._connectNum += 1;
}
}
// 关闭websocket连接
closeWebSocket(){
wx.closeSocket();
this._isClosed = true;
}
}

使用方法

在app.js里面引入,然后在onLaunch里面创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import websocket from './utils/wechat-websocket.js'

//app.js
App({
onLaunch() {
let _this = this;
// 创建websocket对象
this.websocket = new websocket({
// true代表启用心跳检测和断线重连
heartCheck: true,
isReconnection: true
});
// 建立连接
this.linkWebsocket();
// 监听websocket状态
this.websocket.onSocketClosed({
url: this.globalData.websocketUrl,
success(res) { console.log(res) },
fail(err) { console.log(err) }
})
// 监听网络变化
this.websocket.onNetworkChange({
url: this.globalData.websocketUrl,
success(res) { console.log(res) },
fail(err) { console.log(err) }
})
// 监听服务器返回
this.websocket.onReceivedMsg(result => {
console.log('app.js收到服务器内容:' + result.data);
// 要进行的操作
})
},
onHide(){
// 程序后台后的操作--关闭websocket连接
this.websocket.closeWebSocket();
},
onShow(){
// 程序从后台到前台的操作--建立连接
this.linkWebsocket();
}.
linkWebsocket() {
// 建立连接
this.websocket.initWebSocket({
url: this.globalData.websocketUrl,
success(res) { console.log(res) },
fail(err) { console.log(err) }
})
},
getWebSocket() {
// 向其他页面暴露当前websocket连接
return this.websocket;
},
globalData: {
websocketUrl: 'wss://xxx.com/websocket'
}
})