前端封装websocket,实现长连接,心跳检测及断线重连。
参数设置:
@description: 初始化实例属性,保存参数
@param {String} name // ws名称
@param {String} url // ws地址
@param {Number} timeout // 心跳频率,默认20秒
@param {Number} delayTimeout // 延迟重连时间,默认5秒
@param {String} pingInfo // 发送给服务器的心跳信息
@param {String} pingInfoRes // 服务器返回的心跳信息
@param {Function} received // 监听服务器返回信息
js封装类代码:
export class Socket {
constructor({
url,
received,
name = "default",
pingInfo = "Are you still alive",
pingInfoRes = "Yes,I still alive",
timeout = 1000 * 60,
}) {
this.url = url;
this.callback = received;
this.name = name;
this.ws = null;
this.pingInfo = pingInfo;
this.pingInfoRes = pingInfoRes;
this.pingSetTimeout = null;
this.serverTimeoutObj = null;
// 心跳检测频率
this._timeout = timeout;
// 重连延迟避免请求过多
this.connectTimeout = null;
this.isReconnection = false;
this.delayTimeout = 5000;
this.connect();
}
connect(data) {
if (!this.url) {
console.error("WebSocket地址不能为空!");
return;
}
this.ws = new WebSocket(this.url);
// 建立连接
this.ws.onopen = (e) => {
console.log(`${this.name}-WS连接成功`, e);
this._onopen(data);
};
// 接受服务器返回的信息
this.ws.onmessage = (e) => {
// 收到服务器信息,心跳重置
this._resetHeart();
if (typeof this.callback === "function") {
// 如果不是心跳信息
if (e.data !== this.pingInfoRes) {
return this.callback(JSON.parse(e.data));
}
} else {
console.error(`${this.name}-received参数的类型必须为函数`);
}
};
// 关闭连接
this.ws.onclose = (e) => {
console.log(`${this.name}-WS连接关闭`, e);
};
// 报错
this.ws.onerror = (e) => {
console.log(`${this.name}-WS连接报错`, e);
this._reconnect(e);
};
}
_onopen(data) {
// 心跳开启
this._heartCheck();
// 初始化给后台发送数据
// if (data !== undefined) {
return this.ws.send(JSON.stringify({ "type": "9001" }));
// }
}
_resetHeart() {
this._resetSetTimeout("pingSetTimeout");
this._resetSetTimeout("serverTimeoutObj");
this._resetSetTimeout("connectTimeout");
this._heartCheck();
return this;
}
_resetSetTimeout(key) {
this[key] && clearTimeout(this[key]);
}
// 重连
_reconnect() {
const self = this;
if (this.isReconnection) return;
console.log(`${this.name}-WS重连中...`);
this.isReconnection = true;
// 没连接上会一直重连,设置延迟避免请求过多
this._resetSetTimeout("pingSetTimeout");
this._resetSetTimeout("serverTimeoutObj");
this._resetSetTimeout("connectTimeout");
this.connectTimeout = setTimeout(() => {
// 新连接
self.ws.close();
self.ws = null;
self.connect();
self.isReconnection = false;
}, self.delayTimeout);
}
// 心跳
_heartCheck() {
const self = this;
this._resetSetTimeout("pingSetTimeout");
this._resetSetTimeout("serverTimeoutObj");
this.pingSetTimeout = setTimeout(() => {
// 这里发送一个心跳,后端收到后,返回一个心跳消息,
if (self.ws.readyState === 1) {
self.ws.send(`{"type":"9000"}`);
// self.ws.send(JSON.stringify(self.pingInfo));
self.serverTimeoutObj = setTimeout(() => {
console.log(`${self.name}-WS未收到服务心跳信息,重连`);
self._reconnect();
}, self._timeout);
} else {
console.log(`${self.name}-WS状态不正常,重连`);
// 链接状态不正常重连
self._reconnect();
}
}, self._timeout);
}
close() {
this.ws.close();
this.ws = null;
this._resetSetTimeout("pingSetTimeout");
this._resetSetTimeout("serverTimeoutObj");
this._resetSetTimeout("connectTimeout");
console.log(`${this.name}-WS手动关闭了`);
}
}
webScoketApi封装:
let url = '';
if (process.env.NODE_ENV === "production") {
var arrUrl = window.location.host;
url = arrUrl + '/socket/' + process.env.VUE_APP_BASE_API
} else if (process.env.NODE_ENV === "development") {
let uu = process.env.VUE_APP_BASE_URL.slice(process.env.VUE_APP_BASE_URL.indexOf(":") + 3, process.env.VUE_APP_BASE_URL.length)
if (uu.indexOf('/') !== -1) {
uu = uu.slice(0, uu.length - 1)
}
url = uu + '/socket'
}
// http/https
export const webSockApi = window.location.protocol == 'http:' ? `ws://${url}` : `wss://${url}`
其他组件使用:
//引入完Socket和webScoketApi后
initWebSocket() {
if (!this.$store.state.token) return;
let wsurl = webSockApi + `/${this.token}`; // ws地址
// 初始化
this.ws = new Socket({
url: wsurl,
pingInfo: `{"type":"9001"}`, // 给服务器的心跳信息,默认Are you still alive
received: (data) => {
// 监听服务器返回信息
},
});
},