vue項目使用websocket連接問題及解決
vue使用websocket連接
前景
公司做一個包含websocket的項目,我用的是vue做的,開始只有一個組件的要求demo,就將websocket的配置直接放在組件方法中,組件掛載時直接初始化ws,但是后續(xù)組件增加,開始出現(xiàn)多個websocket鏈接的情況,是不允許的。
剛開始的做法是將websocket的方法配置等封裝為一個js文件給各個組件調(diào)用,當離開組件頁面進入新頁面時會斷連舊的ws新建一個ws,以為做到了獨立,但是實際上確實多次的斷連鏈接,十分不便。
思考了挺久找到了解決方法,在此記錄加深記憶
解決過程
要求整個vue項目使用一個ws鏈接,在各組件都要求可以接受發(fā)送消息
首先想到的就是在app.vue下創(chuàng)建我是鏈接,然后給各個小的組件使用ws,做到統(tǒng)一,很簡單的解決思路,我是這么做的
前期已經(jīng)將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中,相關(guān)配置如下:
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; ? ? //沒連接上會一直重連,設(shè)置延遲避免請求過多 ? ? 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(){ ? ? ? ? //這里發(fā)送一個心跳,后端收到后,返回一個心跳消息, ? ? ? ? if (self.ws.readyState === 1) {//如果連接正常 ? ? ? ? ? ?? ? ? ? ? ? ? self.ws.send(heartbeat); //心跳包格式需要自己確定 ? ? ? ? ? }else{//否則重連 ? ? ? ? ? ? reconnect(); ? ? ? ? } ? ? ? ? self.serverTimeoutObj = setTimeout(function() { ? ? ? ? ? ? //超時關(guān)閉 ? ? ? ? ? ? self.ws.close(); ? ? ? ? ? ? reconnect() ? ? ? ? }, self.timeout); ? ? }, self.timeout) } function onmessage(e) { ? ? console.log('接收數(shù)據(jù)',e) ? ? //處理數(shù)據(jù)的地方 ? ? reset(); } function onclose(e) { ? ? console.log('websocket 斷開: ',e); ? } function onerror(e) { ? ? console.log("出現(xiàn)錯誤"); ? ? //重連 ? ? reconnect(); } ? ? export default { ? ? initWebpack, ? ? onmessage, ? ? onclose, ? ? onopen, ? ? onerror }
store.state:
state: { ? ? ? ? permissions: false, ? ? ? ? url: '', ? ? ? ? //ws參數(shù) ? ? ? ? path: '', ? ? ? ? ws: null,//建立的連接 ? ? ? ? lockReconnect: false,//是否真正建立連接 ? ? ? ? timeout: 58*1000,//58秒一次心跳 ? ? ? ? timeoutObj: null,//心跳心跳倒計時 ? ? ? ? serverTimeoutObj: null,//心跳倒計時 ? ? ? ? timeoutnum: null,//斷開 重連倒計時 ? ? ? },
配置之后我在app.vue掛載之后直接初始化ws鏈接:
mounted() { ? ? this.$ws.initWebpack() ? }
發(fā)現(xiàn)是成功的,已經(jīng)將ws鏈接上了,接著就是在各個組件測試一下發(fā)送數(shù)據(jù)的功能:
this.$store.state.ws.send(msg)
神奇的發(fā)現(xiàn),也成功了!
之所以這么簡單,前期的封裝也是占功勞的嘛,至此我的vue只需要一個ws鏈接就可以供整個項目使用,雖然不知道別人的做法是怎么樣,如果有更好的方法也希望大家講解下
vue2全局使用websocket記錄
1、考慮到登錄之后要始終連接服務(wù)器接收消息,所以把websocket實例對象作為模塊拋出,在main.js中引入,使全局都可以獲得ws并且使用相關(guān)方法。
2、由于刷新頁面時,ws會自動斷開連接,所以在App.vue組件掛載時再次連接服務(wù)器。
新建ws模塊文件
該文件位置任意,引入的時候注意路徑即可
export default { ? ? ws: {}, ? ? setWs: function(newWs) { ? ? ? ? this.ws = newWs ? ? }, ? ? start(){// 發(fā)送心跳 ? ? ? ? clearInterval(this.timeoutObj) ? ? ? ? this.timeoutObj = setInterval(() => { ? ? ? ? ? ? if (this.ws && this.ws.readyState == 1) { ? ? ? ? ? ? ? ? console.log('發(fā)送心跳') ? ? ? ? ? ? ? ? this.ws.send(JSON.stringify({ ? ? ? ? ? ? ? ? ? ? //后端需要接收的數(shù)據(jù) ? ? ? ? ? ? ? ? })); ? ? ? ? ? ? } ? ? ? ? }, 10 *1000)//十秒發(fā)一次 ? ? }, ? ? localSocket(userId) {//連接ws,根據(jù)連接服務(wù)器是否需要參數(shù)設(shè)置該方法是否需要接收參數(shù) ? ? ? ? if ("WebSocket" in window) { ? ? ? ? ? ? // console.log("您的瀏覽器支持 WebSocket!"); ? ? ? ? ? ? // location.host ? ? ? ? ? ? this.ws = new WebSocket('這里要填連接服務(wù)器的地址'); ? ? ? ? ? ? this.setWs(this.ws); ? ? ? ? ? ? this.ws.onopen = ()=>{ ? ? ? ? ? ? ? ? console.log('websocket連接成功'); ? ? ? ? ? ? ? ? //連接上之后要發(fā)心跳包 ? ? ? ? ? ? ? ? this.start() ? ? ? ? ? ? }; ? ? ? ? ? ? this.ws.onclose = function () { ? ? ? ? ? ? ? ? // 關(guān)閉 websocket ? ? ? ? ? ? ? ? console.log("連接已關(guān)閉..."); ? ? ? ? ? ? ? ? //斷線重新連接 ? ? ? ? ? ? ? ? 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掛載時再次連接服務(wù)器并且接收消息
mounted(){ ? ? ? this.global.localSocket(userId) ? ? ? //連上之后要接收服務(wù)器發(fā)來的消息 ? ? ? this.global.ws.onmessage = (msg)=>{ ? ? ? ? ? console.log(JSON.parse(msg.data)) ? ? ? ?} }
通過以上方法,任何組件都可以通過this.global.ws獲得websocket實例對象并且使用相關(guān)方法,可能會有些問題,但是我別的問題太多了,這個先放一下吧。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue中實現(xiàn)Monaco Editor自定義提示功能
最近小編接到一個項目,需要在瀏覽器的ide中支持自定義提示功能,接下來通過本文給大家介紹在vue中實現(xiàn)Monaco Editor自定義提示功能,需要的朋友可以參考下2019-07-07Vue項目前后端聯(lián)調(diào)(使用proxyTable實現(xiàn)跨域方式)
這篇文章主要介紹了Vue項目前后端聯(lián)調(diào)(使用proxyTable實現(xiàn)跨域方式),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07