vue使用websocket连接
前景
公司做一个包含websocket的项目,我用的是vue做的,开始只有一个组件的要求demo,就将websocket的配置直接放在组件方法中,组件挂载时直接初始化ws,但是后续组件增加,开始出现多个websocket链接的情况,是不允许的。
刚开始的做法是将websocket的方法配置等封装为一个js文件给各个组件调用,当离开组件页面进入新页面时会断连旧的ws新建一个ws,以为做到了独立,但是实际上确实多次的断连链接,十分不便。
思考了挺久找到了解决方法,在此记录加深记忆
解决过程
要求整个vue项目使用一个ws链接,在各组件都要求可以接受发送消息
首先想到的就是在app.vue下创建我是链接,然后给各个小的组件使用ws,做到统一,很简单的解决思路,我是这么做的
前期已经将ws封装成一个wsconnect.js文件了,那么是否可以将wsconnect注册为全局的方法呢,试了一下果真可行,只需要在main.js中配置:
import wsConnect from "@/assets/js/wsConnect"; Vue.prototype.$ws = wsConnect ? new Vue({ ? render: h => h(App), ? router, ? axios, ? store }).$mount('#app')
说明一下,在wsconnect.js文件中我封装了方法,但是把ws对象放在了vuex的state中,相关配置如下:
wsconnect.js:
import axios from "axios"; import store from "@/store"; ? //websocket ? function initWebpack(){ ? ? var url = store.state.url ? ? var wsurl = '' ? ? axios.get(`${url}/bcall/url`) ?//这是我在从后端拿ws链接的地址 ? ? ? ? .then((res) => ?{ ? ? ? ? ? ? console.log(res.data.data) ? ? ? ? ? ? wsurl = res.data.data ? ? ? ? ? ? store.state.ws = new WebSocket(wsurl); ? ? ? ? ? ? store.state.ws.onopen = onopen; ? ? ? ? ? ? store.state.ws.onmessage = onmessage; ? ? ? ? ? ? store.state.ws.onclose = onclose; ? ? ? ? ? ? store.state.ws.onerror = onerror; ? ? ? ? ? }).catch((err)=> { ? ? ? ? console.log(err) ? ? }) ? } function onopen() { ? ? console.log("连接websocket"); ? ? var params = '{"reqtype":"Query","action":"allexts"}' ? ? store.state.ws.send(params) ? ? start(); } function reconnect() {//重新连接 ? ? var that = store.state; ? ? if(that.lockReconnect) { ? ? ? ? return; ? ? } ? ? that.lockReconnect = true; ? ? //没连接上会一直重连,设置延迟避免请求过多 ? ? that.timeoutnum && clearTimeout(that.timeoutnum); ? ? that.timeoutnum = setTimeout(function () { ? ? ? ? //新连接 ? ? ? ? initWebpack(); ? ? ? ? that.lockReconnect = false; ? ? ? ? that.isFirstGet = true ? ? },5000); } function reset(){//重置心跳 ? ? var that = store.state; ? ? //清除时间 ? ? clearTimeout(that.timeoutObj); ? ? clearTimeout(that.serverTimeoutObj); ? ? //重启心跳 ? ? start(); } function start(){ //开启心跳 ? ? console.log('开启心跳'); ? ? var self = store.state; ? ? self.timeoutObj && clearTimeout(self.timeoutObj); ? ? self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj); ? ? self.timeoutObj = setTimeout(function(){ ? ? ? ? //这里发送一个心跳,后端收到后,返回一个心跳消息, ? ? ? ? if (self.ws.readyState === 1) {//如果连接正常 ? ? ? ? ? ?? ? ? ? ? ? ? self.ws.send(heartbeat); //心跳包格式需要自己确定 ? ? ? ? ? }else{//否则重连 ? ? ? ? ? ? reconnect(); ? ? ? ? } ? ? ? ? self.serverTimeoutObj = setTimeout(function() { ? ? ? ? ? ? //超时关闭 ? ? ? ? ? ? self.ws.close(); ? ? ? ? ? ? reconnect() ? ? ? ? }, self.timeout); ? ? }, self.timeout) } function onmessage(e) { ? ? console.log('接收数据',e) ? ? //处理数据的地方 ? ? reset(); } function onclose(e) { ? ? console.log('websocket 断开: ',e); ? } function onerror(e) { ? ? console.log("出现错误"); ? ? //重连 ? ? reconnect(); } ? ? export default { ? ? initWebpack, ? ? onmessage, ? ? onclose, ? ? onopen, ? ? onerror }
store.state:
state: { ? ? ? ? permissions: false, ? ? ? ? url: '', ? ? ? ? //ws参数 ? ? ? ? path: '', ? ? ? ? ws: null,//建立的连接 ? ? ? ? lockReconnect: false,//是否真正建立连接 ? ? ? ? timeout: 58*1000,//58秒一次心跳 ? ? ? ? timeoutObj: null,//心跳心跳倒计时 ? ? ? ? serverTimeoutObj: null,//心跳倒计时 ? ? ? ? timeoutnum: null,//断开 重连倒计时 ? ? ? },
配置之后我在app.vue挂载之后直接初始化ws链接:
mounted() { ? ? this.$ws.initWebpack() ? }
发现是成功的,已经将ws链接上了,接着就是在各个组件测试一下发送数据的功能:
this.$store.state.ws.send(msg)
神奇的发现,也成功了!
之所以这么简单,前期的封装也是占功劳的嘛,至此我的vue只需要一个ws链接就可以供整个项目使用,虽然不知道别人的做法是怎么样,如果有更好的方法也希望大家讲解下
vue2全局使用websocket记录
1、考虑到登录之后要始终连接服务器接收消息,所以把websocket实例对象作为模块抛出,在main.js中引入,使全局都可以获得ws并且使用相关方法。
2、由于刷新页面时,ws会自动断开连接,所以在App.vue组件挂载时再次连接服务器。
新建ws模块文件
该文件位置任意,引入的时候注意路径即可
export default { ? ? ws: {}, ? ? setWs: function(newWs) { ? ? ? ? this.ws = newWs ? ? }, ? ? start(){// 发送心跳 ? ? ? ? clearInterval(this.timeoutObj) ? ? ? ? this.timeoutObj = setInterval(() => { ? ? ? ? ? ? if (this.ws && this.ws.readyState == 1) { ? ? ? ? ? ? ? ? console.log('发送心跳') ? ? ? ? ? ? ? ? this.ws.send(JSON.stringify({ ? ? ? ? ? ? ? ? ? ? //后端需要接收的数据 ? ? ? ? ? ? ? ? })); ? ? ? ? ? ? } ? ? ? ? }, 10 *1000)//十秒发一次 ? ? }, ? ? localSocket(userId) {//连接ws,根据连接服务器是否需要参数设置该方法是否需要接收参数 ? ? ? ? if ("WebSocket" in window) { ? ? ? ? ? ? // console.log("您的浏览器支持 WebSocket!"); ? ? ? ? ? ? // location.host ? ? ? ? ? ? this.ws = new WebSocket('这里要填连接服务器的地址'); ? ? ? ? ? ? this.setWs(this.ws); ? ? ? ? ? ? this.ws.onopen = ()=>{ ? ? ? ? ? ? ? ? console.log('websocket连接成功'); ? ? ? ? ? ? ? ? //连接上之后要发心跳包 ? ? ? ? ? ? ? ? this.start() ? ? ? ? ? ? }; ? ? ? ? ? ? this.ws.onclose = function () { ? ? ? ? ? ? ? ? // 关闭 websocket ? ? ? ? ? ? ? ? console.log("连接已关闭..."); ? ? ? ? ? ? ? ? //断线重新连接 ? ? ? ? ? ? ? ? setTimeout(() => { ? ? ? ? ? ? ? ? ? ? this.localSocket(userId); ? ? ? ? ? ? ? ? }, 2000); ? ? ? ? ? ? }; ? ? ? ? } else { ? ? ? ? ? ? // 浏览器不支持 WebSocket ? ? ? ? ? ? console.log("您的浏览器不支持 WebSocket!"); ? ? ? ? ? ? this.openNotificationWithIcon('error', '浏览器', '您的浏览器不支持显示消息请更换', 1,1) ? ? ? ? } ? ? }, }?
在main.js中引用ws模块文件
import global from './ws.js' Vue.prototype.global = global
App.vue挂载时再次连接服务器并且接收消息
mounted(){ ? ? ? this.global.localSocket(userId) ? ? ? //连上之后要接收服务器发来的消息 ? ? ? this.global.ws.onmessage = (msg)=>{ ? ? ? ? ? console.log(JSON.parse(msg.data)) ? ? ? ?} }
通过以上方法,任何组件都可以通过this.global.ws获得websocket实例对象并且使用相关方法,可能会有些问题,但是我别的问题太多了,这个先放一下吧。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
查看更多关于vue项目使用websocket连接问题及解决的详细内容...