WebSocket
浏览器通过JavaScript向服务器发出建立WebSocket链接的请求,链接建立后,客户端和服务器端就可以通过TCP链接直接交互数据。WebSocket链接后可以通过send()
方法来向服务器发送数据,并通过onnessage
事件来接受服务器返回的数据。
创建WebSocket对象
let ws = new WebSocket(server);
WebSocket属性
属性 | 描述 |
---|---|
ws.readyState |
WebSocket.CONNECTING : 0正在链接 WebSocket.OPEN : 1 链接成功,可以通信 WebSocket.CLOSING : 2 链接正在关闭 WebSocket.CLOSED : 3 链接已经关闭,或者打开链接失败 |
ws.bufferedAmount |
只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。 |
ws.onopen |
连接建立时触发 |
ws.onmessage |
客户端接收服务端数据时触发 |
ws.onerror |
通信发生错误时触发 |
ws.onclose |
连接关闭时触发 |
ws.binaryType |
指定有链接所传递的二进制数据类型(可选值:blob 、arraybuffer ) |
WebSocket 方法
方法 | 描述 |
---|---|
ws.send() | 使用链接发送数据 |
ws.close() | 关闭链接 |
WebSocket使用
创建WebSocket实例
首先判断当前浏览器是否支持WebSocket
,如果支持则创建WebSocket
实例,并初始化事件函数。
let ws = null;
const server = `ws://xxx.xx.xxx.xxx:xxxx`;// WebSocket服务地址
let createWebSocket = (server) => {
try {
if(window["WebSocket"]){
ws = new WebSocket(server)
}else if(window["MozWebSocket"]){
ws = new MozWebSocket(server)
} else {
Notification({message:"当前浏览器不支持websocket协议,建议使用Chrome浏览器",type:"success"})
}
initEventHandle()// 连接建立时触发
} catch (e) {
console.log("ERR-----------捕获异常", e)
}
};
初始化事件函数
在onerror
与onclose
进行报错或链接断开后的一下业务逻辑操作(如:重连操作)onopen
:初始化状态(如:心跳检测、重连次数)onmessage
:对服务器发送的消息做处理
let initEventHandle = () => {
// 连接报错
ws.onerror = function (evt, e) {
console.log("连接报错");
};
// 连接关闭
ws.onclose = function (evt) {
console.log("连接关闭---" + new Date().toLocaleTimeString());
};
// 链接成功
ws.onopen = function (evt) {
console.log("链接成功");
};
// 接受数据
ws.onmessage = function (evt) {
console.log("收到消息");
};
};
重连机制
当浏览器断开WebSocket
链接时或链接失败时,会出发onclose
与onerror
事件。我们可以在onclose
与onerror
中调用重连方法。为了避免重连方法的过多请求,可以定义一个状态来控制,也可以设置最大重连次数。
let count = 0;// 记录次数
let lockReconnect = false;// 避免ws重复连接
let reconnect = (server) => {
if (count >= 5) return console.log("超出重连次数!");
if (lockReconnect) return false;
lockReconnect = true;
setTimeout(function () { // 设置延迟避免请求过多
console.log("6----------开始重连");
lockReconnect = false;
count++;
}, 5000);
};
心跳检测
为了保证WebSocket
与服务器之间正常通信,可以每隔一段时间通过send()
方法向服务器发送一个心跳信息。在onmessage
拿到返回的心跳就说明连接正常。(服务器收到信息会返回相应的信息)
const heartCheck = {
timeout: 25000, // 设置心跳时间
timeoutObj: null,
serverTimeoutObj: null,
reset: function () {
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
const self = this;
this.timeoutObj = setTimeout(function () {
// 这里发送一个心跳,后端收到后,返回一个心跳消息,onmessage拿到返回的心跳就说明连接正常
ws.send("ping----------Ping");
self.serverTimeoutObj = setTimeout(function () {
// 如果超过一定时间还没重置,说明后端主动断开了
// 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
ws.close();
},self.timeout)
},this.timeout)
}
};
监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
ws.close();
};
在Vue中使用WebSocket
在main.js
中引入全局并挂载到Vue原型上。
import socket from "@/utils/webSocket";
Vue.prototype.startWebSocket = socket.startWebSocket;
完整代码:
// webSocket.js
import {Notification} from "element-ui";
import { getToken } from ‘@/utils/auth‘;
let count = 0;// 记录计数
let lockReconnect = false;//避免ws重复连接
const text1 = "您有新的订单,请及时处理!";
let ws = null;// 判断当前浏览器是否支持WebSocket
const server = `ws://xxx.xx.xxx.xxx:xxxx?Admin-Token=${getToken()}`;// WebSocket服务地址
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
ws.close();
};
// 重连
let reconnect = (server) => {
if (count >= 5) return console.log("超出重连次数!");
if (lockReconnect) return false;
lockReconnect = true;
setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
createWebSocket(server);
lockReconnect = false;
count++;
}, 5000);
};
// 创建实例websocket
let createWebSocket = (server) => {
try {
if(‘WebSocket‘ in window){
ws = new WebSocket(server)
}else if(‘MozWebSocket‘ in window){
ws = new MozWebSocket(server)
} else {
Notification({message:"当前浏览器不支持websocket协议,建议使用现代浏览器",type:"success"})
}
// 连接建立时触发
initEventHandle()
} catch (e) {
console.log("ERR-----------捕获异常", e)
}
};
// 初始化事件函数
let initEventHandle = () => {
// 连接报错
ws.onerror = function (evt, e) {
reconnect(server)
};
// 连接关闭
ws.onclose = function (evt) {
console.log("连接关闭---" + new Date().toLocaleTimeString());
reconnect(server)
};
// 链接成功
ws.onopen = function (evt) {
heartCheck.reset().start();// 心跳检测重置
count = 0;// 重置重连次数
};
// 接受数据
ws.onmessage = function (evt) {// 如果获取到消息,心跳检测重置
heartCheck.reset().start();// 拿到任何消息都说明当前连接是正常的
let eventData = undefined;
try {
eventData = JSON.parse(evt.data);
handMsg(eventData)
}catch (e) {
console.log("捕获异常: 当前返回的数据不能解析;");
console.log("内容:" + evt.data)
}
};
};
// 心跳检测
const heartCheck = {
timeout: 25000, // 设置心跳时间
timeoutObj: null,
serverTimeoutObj: null,
reset: function () {
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
const self = this;
this.timeoutObj = setTimeout(function () {
// 这里发送一个心跳,后端收到后,返回一个心跳消息,onmessage拿到返回的心跳就说明连接正常
ws.send("ping--------------Ping");
self.serverTimeoutObj = setTimeout(function () {
// 如果超过一定时间还没重置,说明后端主动断开了
// 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
ws.close();
},self.timeout)
},this.timeout)
}
};
// 处理消息
let handMsg = (eventData) => {
if (ws.readyState === WebSocket.OPEN) {
if (eventData.code === "2000" && eventData.type === "order_notice") {
Notification({message: text1,type:"warning"})
}
}
};
let startWebSocket = () => {
createWebSocket(server)
};
export default { startWebSocket }
效果图: