一、使用場景
發布者設置需要發布的公告內容、公告接收用戶和發布時間,到達發布時間時及時通知提醒已登錄系統用戶,使用websocke來實現前端與服務器保持長連接,以便實時過去公告信息。
- WebSocket是一種在單個TCP連接上進行全雙工通信的協議。這種協議使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。WebSocket基于TCP傳輸協議,并且復用HTTP的握手通道,即基于HTTP的"keep-alive"機制,允許在一次TCP連接中傳送多個HTTP請求和響應。
- WebSocket的通信過程大致如下:在建立WebSocket連接時,客戶端會向服務器發送一個HTTP請求報文,其中包含升級協議的請求頭。服務器在接收到該請求后會返回一個HTTP響應報文,其中包含升級協議的響應頭。在收到服務器的響應后,客戶端和服務器之間的連接就會升級為WebSocket連接,此時客戶端和服務器之間的通信就不再需要使用HTTP協議的請求和響應報文,而是直接進行雙向數據傳輸。
- WebSocket協議的特點包括: 較少的控制開銷:在連接創建后,服務器和客戶端之間交換數據時,用于協議控制的數據包頭部相對較小。
- 更強的實時性:由于協議是全雙工的,所以服務器可以隨時主動給客戶端下發數據。
- 保持連接狀態:與HTTP不同的是,WebSocket需要先創建連接,這就使得其成為一種有狀態的協議,之后通信時可以省略部分狀態信息。
- 更好的二進制支持:WebSocket定義了二進制幀,相對HTTP,可以更輕松地處理二進制內容。
- 可以支持擴展:WebSocket定義了擴展,用戶可以擴展協議、實現部分自定義的子協議。
- 與HTTP長連接相比,WebSocket連接在數據傳輸效率和實時性方面具有明顯優勢。HTTP長連接中,每次數據交換除了真正的數據部分外,服務器和客戶端還要大量交換HTTP
header,消息交換效率低。而WebSocket連接在建立后,可以直接進行雙向數據傳輸,無需反復建立連接和發送HTTP請求,從而大大提高了數據傳輸效率和實時性。- 總之,WebSocket是一種高效、實時的全雙工通信協議,適用于需要實時通信和數據傳輸的場景。
二、實現過程
- 封裝自定義websocket服務
import config from "./config"/** 自定義websocket服務 */
export default class SocketService {/*** 單例*/static instance = nullstatic get Instance() {if (!this.instance) {this.instance = new SocketService()}return this.instance}/** 和服務端連接的socket對象 */ws = null/** 服務器連接地址 */wsUrl = null/** 連接用戶Id */userId = null/** 存儲回調函數 */callBackMapping = {}/** 標識是否連接成功 */connected = false/** 重新連接間隔(ms) */connectRetryTime = 3000/** 重新連接次數 */connectRetryCount = 0/** 定義連接服務器的方法 */connect(_userId) {// 連接服務器if (!window.WebSocket) {return console.log('您的瀏覽器不支持WebSocket')}// // =============環境判斷===============this.userId = _userId;if (process.env.NODE_ENV == 'development') {this.wsUrl = config.development_config.wsUrl + _userId + ':' + Date.now();}else if (process.env.NODE_ENV == 'debug') {this.wsUrl = config.development_config.wsUrl + _userId + ':' + Date.now();}else if (process.env.NODE_ENV == 'production') {this.wsUrl = config.production_config.wsUrl + _userId + ':' + Date.now();}this.ws = new WebSocket(this.wsUrl)// 連接成功的事件this.ws.onopen = () => {console.log('Socket連接服務端成功,您的連接地址:' + this.wsUrl);this.connected = true// 重置重新連接的次數this.connectRetryCount = 0}// 1.連接服務端失敗// 2.當連接成功之后, 服務器關閉的情況this.ws.onclose = () => {console.log('連接服務端失敗')this.connected = falsethis.connectRetryCount++if (this.connectRetryCount >= 10) {console.log('Socket出錯,已斷開連接');}else{console.log('Socket出錯:第' + this.connectRetryCount + '次重新連接嘗試!')this.connect(this.userId);}}}
}
-
在用戶登錄成功后建立連接,App.vue中也要建立連接(用戶刷新后要重新連接)
login.vue
App.vue
main.js
-
對應通知頁面獲取數據并以彈框的形式渲染
/** 即時通訊相關參數 */im: {ws: null,messageList: [],message: {},},watch: {'im.message': {handler(newVal, oldVal) {if (newVal != oldVal) {console.log('message=>', newVal);this.notVisible = true;setTimeout(() => {this.notVisible = false;}, 10000);}},}},created() {// 檢測瀏覽器是否支持Websocketif (typeof WebSocket == 'undefined') {this.$alert('系統檢測到您的瀏覽器不支持Websocket通信協議,這將會導致您無法正常進行課堂互動!建議您更換瀏覽器進行觀看!', '警告', {confirmButtonText: '知道了',callback: () => { }});}else {this.im.ws = this.$socket.wsvar retry = setInterval(() => {if (this.im.ws == null) {this.im.ws = this.$socket.ws} else {this.initIM();clearInterval(retry)}}, 1000);}},/** 初始化即時通訊 */initIM() {var _this = this;// 接收消息// console.log(_this.im.ws);_this.im.ws.onmessage = function (event) {var message = JSON.parse(event.data);_this.im.message = message.data;// console.log(_this.im.message);}// 出現錯誤_this.im.ws.onerror = function (error) {_this.$message.error('即時通訊出現錯誤');console.log("即時通訊出現錯誤:", error);};},