uni-app使用websocket(心跳机制)

5,662 阅读4分钟

在使用websocket的过程中,有时候会遇到网络断开的情况,但是在网络断开的时候服务器端并没有触发onclose的事件。这样会有:服务器会继续向客户端发送多余的链接,并且这些数据还会丢失。所以就需要一种机制来检测客户端和服务端是否处于正常的链接状态。因此就有了websocket的心跳了。还有心跳,说明还活着,没有心跳说明已经挂掉了。

1. 为什么叫心跳包呢?

它就像心跳一样每隔固定的时间发一次,来告诉服务器,我还活着。

2. 什么是心跳机制?

心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制。

实现方法?如下代码:
class wsRequest {

	constructor(url, time) {
		this.status = null; // websocket是否关闭
		this.lockReconnect = false //避免重复连接
		this.url = url

		//心跳检测
		this.timeout= time //多少秒执行检测
		this.timeoutObj= null //检测服务器端是否还活着
		this.reconnectTimeOutObj= null //重连之后多久再次重连

		try {
			return this.initRequest()
		} catch (e) {
			console.log('catch');
			this.reconnect();
		}
	}

	initRequest() {
		this.socketTask = uni.connectSocket({
			url: this.url, //接口地址。
			success: () => {
				console.log('连接成功');
				// 返回实例
				return this.socketTask
			}
		})
		
		this.socketTask.onOpen(res => {
			console.log(res, '连接打开');
			// 清除重连定时器
			clearTimeout(this.reconnectTimeOutObj)
			// 开启检测
			this.start()
			
		})

		// 如果希望websocket连接一直保持,在close或者error上绑定重新连接方法。
		this.socketTask.onClose((res) => {
			console.log(res, '连接关闭');
			this.reconnect();
		})

		this.socketTask.onError((res) => {
			console.log(res, '连接错误');
			this.reconnect();
		})
		
		this.socketTask.onMessage(res => {
			//接受任何消息都说明当前连接是正常的
			this.reset();
			console.log(res, 'pong');
		})

	}

	send(value) {
		return new Promise((resovle,reject)=>{
			this.socketTask.send({
				data: value,
				success:()=>{
					resovle('发送成功')
				}
			})
		})
	}

	// reset和start方法主要用来控制心跳的定时。
	reset(){
		// 清除定时器重新发送一个心跳信息
		clearTimeout(this.timeoutObj);
     this.start();
	}
	start(){
		this.timeoutObj = setTimeout(() => {
			//这里发送一个心跳,后端收到后,返回一个心跳消息,
			//onmessage拿到返回的心跳就说明连接正常
			console.log('ping');
			this.socketTask.send({data:"ping"});
			
		}, this.timeout)
	}

	// 重连
	reconnect() {
		// 防止多个方法调用,多处重连
		if (this.lockReconnect) {
			return;
		};
		this.lockReconnect = true;
		
		console.log('准备重连');
		
		//没连接上会一直重连,设置延迟避免请求过多
		this.reconnectTimeOutObj = setTimeout(()=>{
			// 重新连接
			this.initRequest()

			this.lockReconnect = false;
		}, 4000);
	}

	// 手动关闭
	close() {
		this.socketTask.close()
	}
}

module.exports = wsRequest

具体的思路如下:

1.创建一个wsRequest类,初始化构造函数的数据

class wsRequest {

	constructor(url, time) {
		this.status = null; // websocket是否关闭
		this.lockReconnect = false //避免重复连接
		this.url = url
	
		//心跳检测
		this.timeout= time //多少秒执行检测
		this.timeoutObj= null //检测服务器端是否还活着
		this.reconnectTimeOutObj= null //重连之后多久再次重连
	
		try {
			return this.initRequest()
		} catch (e) {
			console.log('catch');
			this.reconnect();
		}
	}
}

2.第二步调用initRequest方法,该方法内调用 uni-app的websocket API:

initRequest() {
	this.socketTask = uni.connectSocket({
		url: this.url, //接口地址。
		success: () => {
			console.log('连接成功');
			
			// 返回实例
			return this.socketTask
		}
	})
		
	this.socketTask.onOpen(res => {
		console.log(res, '连接打开');
	})

	this.socketTask.onClose((res) => {
		console.log(res, '连接关闭');
	})

	this.socketTask.onError((res) => {
		console.log(res, '连接错误');
	})
	
	this.socketTask.onMessage(res => {
		console.log(res);
	})

}

2.1send发送事件

send(value) {
	//这段返回可要可不要
	//return new Promise((resovle,reject)=>{
		this.socketTask.send({
			data: value,
			success:()=>{
				resovle('发送成功')
			}
		})
	//})
}

3.重连 reconnect 代码如下:

reconnect() {
	// 防止多个方法调用(onError/onError都会调用),多处重连
	if (this.lockReconnect) {
		return;
	};
	this.lockReconnect = true;
	
	console.log('准备重连');
	
	//没连接上会一直重连,设置延迟避免请求过多
	this.reconnectTimeOutObj = setTimeout(()=>{
		// 重新连接
		this.initRequest()
		this.lockReconnect = false;
	}, 5000);
}

重连方法写完后,在onClose,onError监听事件里调用 reconnect

4.心跳检测,发送心跳包

reset(){
	// 清除定时器重新发送一个心跳信息
	clearTimeout(this.timeoutObj);
     this.start();
}
start(){
	this.timeoutObj = setTimeout(() => {
		//这里发送一个心跳,后端收到后,返回一个心跳消息,
		//onmessage拿到返回的心跳就说明连接正常
		console.log('ping');
		this.socketTask.send({data:"ping"});
		
	}, this.timeout)
}

onOpen链接打开的时候开启检测,在onMessage监听收到消息的时候重置定时器

this.socketTask.onOpen(res => {
	console.log(res, '连接打开');
	
	// 清除重连定时器
	clearTimeout(this.reconnectTimeOutObj)
	
	// 开启检测
	this.start()
	
})

this.socketTask.onMessage(res => {
	//接受任何消息都说明当前连接是正常的
	this.reset();
	console.log(res, 'pong');
})

实现心跳检测的思路是:每隔一段固定的时间,向服务器端发送一个ping数据,如果在正常的情况下,服务器会返回一个pong给客户端,如果客户端通过onMessage事件能监听到的话,说明请求正常,这里使用了一个定时器,每隔5秒的情况下,如果是网络断开的情况下,在指定的时间内服务器端并没有返回心跳响应消息,因此服务器端断开了,因此这个时通过onClose事件监听到。因此在onClose事件内,我们可以调用reconnect事件进行重连操作。