vue使用websocket實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送功能
需求:使用websocket不借助插件實(shí)現(xiàn)發(fā)布,訂閱,網(wǎng)絡(luò)斷開(kāi)重連,單點(diǎn)登錄后擠號(hào)的功能
1.單點(diǎn)登錄(同一賬號(hào)同一時(shí)間只有一個(gè)在線(xiàn),禁止多用戶(hù)登錄)
實(shí)現(xiàn):在用戶(hù)登錄之后獲取到token令牌并且存入到本地,可以判斷token令牌是否失效來(lái)讓用戶(hù)退出登錄,websocket的操作是讓用戶(hù)登錄后連接到websocket并且發(fā)送指令,這邊發(fā)送的指令是后端給的,之后前端進(jìn)行接受消息,如果消息是退出登錄的直接讓他清空本地并且跳轉(zhuǎn)到登錄頁(yè)就行
1.登錄獲取token令牌并且存儲(chǔ)到localStorage
2.在layout也就是頁(yè)面主體框架拿到token并且去連接websocket
3.連接成功后直接發(fā)送指令,之后再去監(jiān)聽(tīng)返給前端的消息之后實(shí)現(xiàn)退出操作
url = `${protocol}://websocket的地址,要后端給?token=${token}`;,
這個(gè)我舉個(gè)例子,連接地址應(yīng)該是這樣的:ws://127.0.0.1:8080?token=362466325,
ws.send(`msg:${this.data.id}`);這個(gè)也是后端定的要把賬戶(hù)的id給他,這樣去監(jiān)聽(tīng)登錄
重連,之后消息返回loginOut后做退出登錄的操作,如果鏈接因?yàn)楦鞣N原因關(guān)閉了,直接去請(qǐng)求重連。
retryCount: 0,
maxRetryCount: 5,
retryInterval: 2000, // 重試間隔時(shí)間,單位:毫秒
注意??!websocket不能設(shè)置請(qǐng)求頭攜帶token好像,試了很多次都不行,用ws插件也不行,只能拼接token給后端了
let ws; let url = ""; export default { mounted() { this.connectWebsocket(); }, methods: { connectWebsocket() { let protocol = "ws"; if (typeof WebSocket === "undefined") { console.log("您的瀏覽器不支持WebSocket"); return; } else { if (window.location.protocol == "https:") { protocol = "wss"; } let token = localStorage.getItem("token"); url = `${protocol}://websocket的地址,要后端給?token=${token}`; // 打開(kāi)一個(gè)ws ws = new WebSocket(url); ws.onopen = () => { // 發(fā)送數(shù)據(jù) console.log("ws已連接??!"); ws.send(`msg:${this.data.id}`); // this.$message.success("ws已連接?。?); }; // 發(fā)生錯(cuò)誤時(shí) ws.onerror = (evt) => { console.log("ws錯(cuò)誤:", evt); }; // 關(guān)閉連接 ws.onclose = (event) => { console.warn("WebSocket 已關(guān)閉"); console.log("關(guān)閉代碼:", event.code); console.log("關(guān)閉原因:", event.reason); // 處理連接斷開(kāi)事件 this.handleWebSocketClose(); }; ws.onmessage = (evt) => { if (evt.data == "loginOut") { // 此時(shí)要做清空數(shù)據(jù)的操作 this.$message.warning("您的帳號(hào)在另一地點(diǎn)登錄,您已被迫下線(xiàn)!!"); this.$router.replace("/"); localStorage.clear(); ws.close(); ws.onclose = () => { console.log("ws斷開(kāi)連接成功"); }; } console.log(evt, "接收到的消息"); }; this.$bus.$emit("Websocket", ws); } }, handleWebSocketClose() { if (this.retryCount < this.maxRetryCount) { console.log(`正在嘗試第 ${this.retryCount + 1} 次重連...`); setTimeout(() => { this.connectWebsocket(); this.retryCount++; }, this.retryInterval); } else { console.error("WebSocket 連接失敗,已達(dá)到最大重試次數(shù)"); } }, } }
2.發(fā)布訂閱
注意??!這邊每次發(fā)布的時(shí)候都應(yīng)該重新連一個(gè)新的消息,不然和之前的登錄的消息搞混了就不好了,特別是在做操作的時(shí)候,比如el-table的編輯操作這些,每次關(guān)閉彈窗肯定要關(guān)閉websocket,如果和登錄的消息搞混了,關(guān)閉彈窗就不能實(shí)時(shí)接收到單點(diǎn)登錄傳來(lái)的消息了
這個(gè)connectWebsocket和上面的不是一個(gè),這個(gè)是需要實(shí)時(shí)推送頁(yè)面的websocket連接,不會(huì)影響全局的單點(diǎn)登錄的。
let websocket; let url = ""; export default { connectWebsocket(data) { let protocol = "ws"; if (typeof WebSocket === "undefined") { console.log("您的瀏覽器不支持WebSocket"); return; } else { if (window.location.protocol == "https:") { protocol = "wss"; } let token = localStorage.getItem("token"); url = `${protocol}://后端的給的地址?token=${token}`; // 打開(kāi)一個(gè)websocket websocket = new WebSocket(url); websocket.onopen = () => { // 發(fā)送數(shù)據(jù) // console.log("websocket已連接?。?); websocket.send(data); this.$message.success("websocket已連接?。?); }; // 發(fā)生錯(cuò)誤時(shí) websocket.onerror = (evt) => { console.log("websocket錯(cuò)誤:", evt); }; // 關(guān)閉連接 websocket.onclose = (event) => { console.warn("WebSocket 已關(guān)閉"); console.log("關(guān)閉代碼:", event.code); console.log("關(guān)閉原因:", event.reason); // 處理連接斷開(kāi)事件 this.handleWebSocketClose(data); }; } }, handleWebSocketClose(data) { if (this.retryCount < this.maxRetryCount) { console.log(`正在嘗試第 ${this.retryCount + 1} 次重連...`); setTimeout(() => { this.connectWebsocket(data); this.retryCount++; }, this.retryInterval); } else { this.$message.error("WebSocket 連接失敗!!"); console.error("WebSocket 連接失敗,已達(dá)到最大重試次數(shù)"); } }, }
2.1模擬編輯操作需要發(fā)布消息
1.點(diǎn)擊編輯后打開(kāi)并且實(shí)時(shí)接收
updData(row) { this.connectWebsocket(`data_imei:${row.id}`); websocket.onmessage = (evt) => { //如果收到的消息是msgUpd if(evt.data=='msgUpd'){ let data = JSON.parse(evt.data); //把得到的數(shù)據(jù)進(jìn)行json轉(zhuǎn)換之后再給tableData進(jìn)行展示就行 let tableData.unshift(data) //也不能一直接受吧,那數(shù)據(jù)得多少啊,定義一下接收到多少條后截取 if (tableData.length > 500) { tableData.splice(500); } } } }
2.關(guān)閉彈窗后需要斷開(kāi)連接
closeWebSocket() { if (websocket != null) { websocket.close(); websocket.onclose = () => { console.log("websocket斷開(kāi)連接成功"); }; } },
3.在離開(kāi)websocket推送頁(yè)面后也關(guān)閉連接
destroyed() { if (websocket != null) { websocket.close(); websocket.onclose = () => { console.log("websocket斷開(kāi)連接成功"); }; } },
到此這篇關(guān)于vue使用websocket實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送功能的文章就介紹到這了,更多相關(guān)vue websocket實(shí)時(shí)數(shù)據(jù)推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue中$emit調(diào)用父組件異步方法模擬.then實(shí)現(xiàn)方式
這篇文章主要介紹了Vue中$emit調(diào)用父組件異步方法模擬.then實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-09-09基于element-ui對(duì)話(huà)框el-dialog初始化的校驗(yàn)問(wèn)題解決
這篇文章主要介紹了基于element-ui對(duì)話(huà)框el-dialog初始化的校驗(yàn)問(wèn)題解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09Vue函數(shù)式組件的應(yīng)用實(shí)例詳解
這篇文章主要介紹了Vue函數(shù)式組件的應(yīng)用實(shí)例詳解,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08從零搭建一個(gè)vite+vue3+ts規(guī)范基礎(chǔ)項(xiàng)目(搭建過(guò)程問(wèn)題小結(jié))
這篇文章主要介紹了從零搭建一個(gè)vite+vue3+ts規(guī)范基礎(chǔ)項(xiàng)目,本項(xiàng)目已vite開(kāi)始,所以按照vite官方的命令開(kāi)始,對(duì)vite+vue3+ts項(xiàng)目搭建過(guò)程感興趣的朋友一起看看吧2022-05-05在Vue2項(xiàng)目中使用Mock.js的詳細(xì)教程
Mock.js?是一個(gè)用于生成隨機(jī)數(shù)據(jù)和攔截?Ajax?請(qǐng)求的?JavaScript?庫(kù),它非常適合在前端開(kāi)發(fā)中模擬后端?API,尤其是在前后端分離的開(kāi)發(fā)模式下,本文給大家介紹了如何在Vue2項(xiàng)目中使用Mock.js,需要的朋友可以參考下2024-10-10