WebSocket的介紹:
WebSocket 是一種在客戶端和服務器之間進行全雙工、雙向通信的協議。它是基于 HTTP 協議,但通過升級(HTTP 升級請求)將連接轉換為 WebSocket 協議,從而提供更高效的實時數據交換。
WebSocket 的特點:
-
雙向通信:與傳統的 HTTP 協議只能從客戶端向服務器發送請求并等待響應不同,WebSocket 可以實現服務器主動向客戶端推送數據,支持雙向通信。
-
持久連接:WebSocket 連接建立后,它是持久的,可以在不重新建立連接的情況下進行多次數據交換。相比于傳統的 HTTP 每次請求都需要建立新的連接,WebSocket 減少了很多開銷。
-
實時性:由于 WebSocket 的全雙工通信特性,它非常適合需要實時更新數據的應用場景,如即時聊天、在線游戲、股票行情等。
-
低延遲:WebSocket 建立連接后,數據可以隨時在客戶端和服務器之間交換,而且沒有 HTTP 協議中的請求和響應過程,因此延遲非常低。
-
協議格式:WebSocket 協議位于應用層與 TCP 層之間,它的標準端口是 80(非加密連接)和 443(加密連接)。
WebSocket 工作原理:
- 連接建立:客戶端發起一個 HTTP 請求,并通過 HTTP 升級請求(
Upgrade
?請求頭)向服務器請求升級協議為 WebSocket。 - 協議升級:如果服務器支持 WebSocket 協議,它會響應?
101 Switching Protocols
,并升級為 WebSocket 協議。此時,WebSocket 連接建立成功。 - 數據交換:一旦連接建立,客戶端和服務器可以在同一連接上發送和接收消息,直到連接被關閉。
- 連接關閉:無論是客戶端還是服務器,都可以主動發起關閉連接。連接關閉時,雙方會互相發送關閉幀(
Close Frame
)來通知對方。
項目需求:
由于最近項目上的大屏接口要換成WebSocket進行實時數據展示,于是需要對WebSocket進行封裝,主要目標是要實現與后端持續保持心跳連接,不要讓WebSocket中斷;例如每10秒就要和后端通訊一次,發送和后端溝通好固定的心跳標識符,后端拿到心跳標識符就會持續保持連接,如果一直沒有收到前端返回的心跳標識符,那么就會中斷WebSocket的連接。
源代碼
export default class WebSocketClient {constructor(url, callback) {this.url = url; // WebSocket 服務器的 URLthis.callback = callback; // 回調方法,用于接收數據this.ws = null; // WebSocket 實例this.heartbeatInterval = 20000; // 心跳間隔(20秒)this.pingTimeout = 10000; // ping 超時時間(10秒)this.heartbeatTimer = null; // 用于存儲心跳定時器this.pingTimer = null; // 用于存儲 ping 超時定時器this.reconnect = true; // 用于判斷是否需要重連}// 啟動 WebSocket 連接start() {this.ws = new WebSocket(this.url);this.ws.onopen = () => {console.log("WebSocket連接成功");this.reconnect = true; // 連接成功,允許重連this.startHeartbeat(); // 連接成功后開始心跳};this.ws.onmessage = (event) => {this.callback(event.data); // 調用回調方法};this.ws.onerror = (error) => {console.error("WebSocket異常:", error);};this.ws.onclose = (event) => {console.log("WebSocket關閉.");clearInterval(this.heartbeatTimer); // 清除心跳定時器clearTimeout(this.pingTimer); // 清除 ping 超時定時器if (this.reconnect && event.code !== 1000) { // 如果是非正常關閉,進行重連console.log("嘗試重新連接...");setTimeout(() => {this.start(); // 5秒后重新連接}, 5000);}};}// 發送數據到服務器send(message) {if (this.ws && this.ws.readyState === WebSocket.OPEN) {this.ws.send(message);} else {console.error("消息發送失敗.");}}// 啟動心跳機制startHeartbeat() {this.heartbeatTimer = setInterval(() => {if (this.ws.readyState === WebSocket.OPEN) {this.send(JSON.stringify({ type: "heartbeat", data: "pong" })); // 與后端約定的心跳標識符,用于保持持續連接}}, this.heartbeatInterval);// 設置 ping 超時機制this.pingTimer = setTimeout(() => {if (this.ws.readyState !== WebSocket.OPEN) {console.error("超時關閉連接.");this.ws.close();}}, this.pingTimeout);}// 主動關閉連接close() {this.reconnect = false; // 主動關閉時不再進行重連if (this.ws) {this.ws.close(1000, 'Closed by client'); // 主動關閉時使用 code 1000 表示正常關閉}}
}
用法
import WebSocketClient from '@/request/ws'export default {data(){return{wsClient:null}},mounted(){this.wsClient = new WebSocketClient('ws://192.168.31.21:8090/ws', this.getWSMessage);this.wsClient.start()},methods:{getWSMessage(data){console.log(data,'ddddddddddddddd')},sendMessage(){let obj = { type: "555", data: "111111" }this.wsClient.send(JSON.stringify(obj))}},beforeDestroy() {this.wsClient.close()}
}