websocket使用步骤及相关解析
一、步骤及相关解析
1.确定需要开启并连接websocket的条件 ,以下简称ws
mounted() {
//确定本地是否存入用户id (如果有,代表用户已登入系统)
let userInfo = JSON.parse(localStorage.getItem("userInfo"));
this.id = userInfo.id;
if (this.id) {
this.initSocket();
}
},
ps: 确定本地是否存入用户id (如果有,代表用户已登入系统)
2.确定需要开启并连接websocket的条件
// 2.确定用户浏览器是否支持WebSocket
initSocket() {
if ("WebSocket" in window) {
// let tcp = location.protocol === 'https:' ? 'wss:' : 'ws:';
// 2-1.如果已有ws开启,先关闭一次 进行我们自己的配置
this.ws && this.ws.close();
// 2-2.生产环境和非生产环境的协议配置 主要变量为 project 和 uid
if(process.env.VUE_APP_TITLE === "stage"){
this.wsUrl = `ws://test.ws.chiefgr.com/?project=jd-shop&uid=` + this.id;
}else{
this.wsUrl = 'ws://ws.chiefgr.com/?project=jd-shop&uid=' + this.id;
}
// 2-3. 配置一个我们对应的ws new WebSocket(this.wsUrl);
this.initWebSocket();
} else {
this.$notify({
message: "当前浏览器不支持消息通知,请升级或更换浏览器!",
position: "bottom-right",
duration: 5000
});
}
},
ps: 判断用户浏览器是否支持ws,若支持,则进行我们需要的相关配置。
注:以下是ws事件方法:
// ws事件方法
initWebSocket() {
this.ws = new WebSocket(this.wsUrl);
this.ws.onopen = this.wsOpen; //连接建立时触发
this.ws.onmessage = this.wsMessage; //客户端接收服务端数据时触发
this.ws.onerror = this.wsError; //通信发生错误时触发
this.ws.onclose = this.wsClose; //连接关闭时触发
},
先把完整代码贴上来 后面有时间再整理步骤解析,代码里的解析其实已经挺详细了
最后:完整代码流程
import { exportDownload } from "@/api/user";
export default {
data() {
return {
wsUrl: "",
id: "",
token: "",
ws: "", //建立的连接
lockReconnect: false, //是否真正建立连接
timeout: 45 * 1000, //30秒一次心跳
timeoutObj: null, //心跳心跳倒计时
serverTimeoutObj: null, //心跳倒计时
timeoutnum: null, //断开 重连倒计时
notificationStatus: false, // 系统通知
}
},
created() {
this.notifyMeAuth();
},
mounted() {
// 1. 确定本地是否存入用户id
let userInfo = JSON.parse(localStorage.getItem("userInfo"));
this.id = userInfo.id;
if (this.id) {
// 1-1. 如果存在,代表用户已登入系统 开启连接websocket(下面简称ws)
this.initSocket();
}
},
beforeDestroy() {
this.id = "";
this.timeoutnum && clearTimeout(this.timeoutnum);
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.ws && this.ws.close();
},
methods: {
// 2.确定用户浏览器是否支持WebSocket
initSocket() {
if ("WebSocket" in window) {
// let tcp = location.protocol === 'https:' ? 'wss:' : 'ws:';
// 2-1.如果已有ws开启,先关闭一次 进行我们自己的配置
this.ws && this.ws.close();
// 2-2.生产环境和非生产环境的协议配置 主要变量为 project 和 uid
if(process.env.VUE_APP_TITLE === "stage"){
this.wsUrl = `ws://test.ws.chiefgr.com/?project=jd-shop&uid=` + this.id;
}else{
this.wsUrl = 'ws://ws.chiefgr.com/?project=jd-shop&uid=' + this.id;
}
// 2-3. 配置一个我们对应的ws new WebSocket(this.wsUrl);
this.initWebSocket();
} else {
this.$notify({
message: "当前浏览器不支持消息通知,请升级或更换浏览器!",
position: "bottom-right",
duration: 5000
});
}
},
// ws事件方法
initWebSocket() {
this.ws = new WebSocket(this.wsUrl);
this.ws.onopen = this.wsOpen; //连接建立时触发
this.ws.onmessage = this.wsMessage; //客户端接收服务端数据时触发
this.ws.onerror = this.wsError; //通信发生错误时触发
this.ws.onclose = this.wsClose; //连接关闭时触发
},
//重置心跳
reset() {
//清除时间
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
//重启心跳
this.start();
},
// 3.连接成功,发一个心跳给服务器 表示我们已准备好
wsOpen() {
console.log("连接 成功", new Date());
// this.wsSend();
// 开启心跳
this.start();
},
//开启心跳
start() {
var that = this;
that.timeoutObj && clearTimeout(that.timeoutObj);
that.serverTimeoutObj && clearTimeout(that.serverTimeoutObj);
that.timeoutObj = setTimeout(function() {
//3-1.这里发送一个心跳,后端收到后,返回一个心跳消息,
if (that.ws.readyState == 1) { //readyState == 1 :连接已建立,可以通信
//如果连接正常 后端返回了信息,进入 6.数据接收
that.ws.send("heartCheck");
} else {
//否则重连 //readyState == 0 :连接尚未建立; 2:连接正在关闭; 3:连接已经关闭或不能打开
that.reconnect();
}
// 3-2.发送心跳超时,则关闭ws
that.serverTimeoutObj = setTimeout(function() {
//超时关闭 如果用户处于登录状态,则重连ws
that.ws.close();
}, that.timeout);
}, that.timeout);
},
// 6.数据接收
wsMessage(res) {
let data = JSON.parse(res.data);
let dom = "";
// 根据返回的数据 判定是下载 还是消息通知 或者其他 (自行约定)
if (data.title) {
this.$store.dispatch("informLog/setNew", true);
if (data.type == "App\\Notifications\\ExportReady") {
// 6-1.下载 调下载接口exportDownload
dom = `<div>${data.filename}</div>`;
let newData = {
filename: data.filename
};
exportDownload(newData)
.then(res => {
let name = data.filename;
let url = window.URL.createObjectURL(res.data);
let link = document.createElement("a");
link.style.display = "none";
link.href = url;
link.setAttribute("download", name);
document.body.appendChild(link);
link.click();
})
.catch(() => {
this.$notify.error("下载错误");
});
} else {
// 6-2.其他通知
dom = data.content;
let text = "";
if (data.content) {
text = data.content.replace(/<.*?>/g, "");
}
// 发送桌面通知
this.notifyMe({
title: data.title,
msg: text
});
}
// 7.接收到数据之后 (不管是哪种类型,在系统中调起弹窗发送通知)
this.$notify({
title: data.title,
dangerouslyUseHTMLString: true,
message: dom,
position: "bottom-right",
duration: 15000
});
}
// 8.收到服务器信息,心跳重置 {"code":2,"api_version":"1.12.4"}
if (data.code == 2) {
this.reset();
}
},
// 发送消息
wsSend() {
this.ws.send(
JSON.stringify({
id: window.btoa(this.id)
})
);
},
// 4.关闭
wsClose() {
console.log("连接 关闭", new Date());
//4-1. 用户处于登录状态,重连ws
if (this.id) {
this.reconnect();
}
},
// 错误
wsError(err) {
console.log("连接 错误", new Date());
//重连
this.reconnect();
},
// 5.重连ws
reconnect() {
//重新连接
var that = this;
if (that.lockReconnect) {
return;
}
that.lockReconnect = true;
//没连接上会一直重连,设置延迟避免请求过多
that.timeoutnum && clearTimeout(that.timeoutnum);
that.timeoutnum = setTimeout(function() {
//新连接
that.initWebSocket();
that.lockReconnect = false;
}, 5000);
},
// 系统 获取通知授权
notifyMeAuth() {
let that = this;
// 先检查浏览器是否支持
if (!("Notification" in window)) {
if(!this.ddEvn){
alert("此浏览器不支持桌面通知");
}
}
// 检查用户是否同意接受通知
else if (Notification.permission === "granted") {
that.notificationStatus = true;
}
// 否则我们需要向用户获取权限
// else if (Notification.permission !== 'denied')
else {
Notification.requestPermission(function(permission) {
// 如果用户同意,就可以向他们发送通知
if (permission === "granted") {
that.notificationStatus = true;
}
});
}
},
// 系统 通知
notifyMe(obj) {
if (this.notificationStatus) {
let { title, msg } = obj;
new Notification(title, {
body: msg
});
}
}
}
}