在vue中使用SockJS實現webSocket通訊

慢思考快行動發表於2019-03-04

最近接到一個業務需求,需要做一個聊天資訊的實時展示的介面,這就需要和伺服器端建立webSocket連線,從而實現資料的實時獲取和檢視的實時重新整理.在此將我的實現記錄下來,希望可以給有同樣需求的人一些幫助.廢話少說,下面我就來講一下我的實現過程:

前提

要進行文章中的程式碼的測試,需要服務端端開發人員配合你,提供相關的通訊介面.來完成客戶端和服務端的通訊.實現通訊,我們需要用到另個模組sockjs-client模組和stomjs模組,接下來我會先對這兩個模組做一個簡單的介紹.

稍後我會寫一篇使用NodeJS+SockJS實現視屏彈幕的功能的文章,敬請期待~

關於實時通訊

實現實時通訊,我們通常有三種方法:

  • ajax輪詢
    ajax輪詢的原理非常簡單,讓瀏覽器每隔幾秒就像伺服器傳送一個請求,詢問伺服器是否有新的資訊.
  • http 長輪詢
    長輪詢的機制和ajax輪詢差不多,都是採用輪詢的方式,不過才去的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說,客戶端發起連結後,如果沒有訊息,就一直不返回response給客戶端.知道有新的訊息才返回,返回完之後,客戶端再此建立連線,周而復始.
  • WebSocket
    WebSocket是HTML5開始提供的一種在單個TCP連線上進行全雙工通訊的協議.在WebSocket API中,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以資料互相傳送,不需要繁瑣的詢問和等待.
    從上面的介紹很容易看出來,ajax輪詢和長輪詢都是非常耗費資源的,ajax輪詢需要伺服器有很快的處理速度和資源,http長輪詢需要有很高的併發,也就是同時接待客戶的能力.而WebSocket,只需要經過一次HTTP請求,就可以與服務端進行源源不斷的訊息收發了.

sockjs-client

sockjs-client是從SockJS中分離出來的用於客戶端使用的通訊模組.所以我們就直接來看看SockJS.
SockJS是一個瀏覽器的JavaScript庫,它提供了一個類似於網路的物件,SockJS提供了一個連貫的,跨瀏覽器的JavaScriptAPI,它在瀏覽器和Web伺服器之間建立了一個低延遲,全雙工,跨域通訊通道.
你可能會問,我為什麼不直接用原生的WebSocket而要使用SockJS呢?這得益於SockJS的一大特性,一些瀏覽器中缺少對WebSocket的支援,因此,回退選項是必要的,而Spring框架提供了基於SockJS協議的透明的回退選項。SockJS提供了瀏覽器相容性,優先使用原生的WebSocket,如果某個瀏覽器不支援WebSocket,SockJS會自動降級為輪詢.

stomjs

STOMP(Simple Text-Orientated Messaging Protocol) 面向訊息的簡單文字協議;
WebSocket是一個訊息架構,不強制使用任何特定的訊息協議,它依賴於應用層解釋訊息的含義.
與HTTP不同,WebSocket是處在TCP上非常薄的一層,會將位元組流轉化為文字/二進位制訊息,因此,對於實際應用來說,WebSocket的通訊形式層級過低,因此,可以在 WebSocket 之上使用STOMP協議,來為瀏覽器 和 server間的 通訊增加適當的訊息語義。

STOMP與WebSocket 的關係:

  1. HTTP協議解決了web瀏覽器發起請求以及web伺服器響應請求的細節,假設HTTP協議不存在,只能使用TCP套接字來編寫web應用,你可能認為這是一件瘋狂的事情;
  2. 直接使用WebSocket(SockJS)就很類似於使用TCP套接字來編寫web應用,因為沒有高層協議,就需要我們定義應用間傳送訊息的語義,還需要確保連線的兩端都能遵循這些語義;
  3. 同HTTP在TCP套接字上新增請求-響應模型層一樣,STOMP在WebSocket之上提供了一個基於幀的線路格式層,用來定義訊息語義.

程式碼實現

程式碼中除了最基本的連線,還設定了一個定時器,每隔十秒傳送一條資料到伺服器端,如果發生錯誤,catch這個錯誤,重新建立連線.

// 安裝並引入相關模組
import SockJS from  `sockjs-client`;  
import  Stomp from `stompjs`;
export default {
    data() {
      return {
        dataList: []
      };
    },
    mounted:function(){
      this.initWebSocket();
    },
    beforeDestroy: function () {
      // 頁面離開時斷開連線,清除定時器
      this.disconnect();
      clearInterval(this.timer);
    },
    methods: {
      initWebSocket() {
        this.connection();
        let self = this;
        // 斷開重連機制,嘗試傳送訊息,捕獲異常發生時重連
        this.timer = setInterval(() => {
          try {
            self.stompClient.send("test");
          } catch (err) {
            console.log("斷線了: " + err);
            self.connection();
          }
        }, 5000);
      },
      removeTab(targetName) {
        console.log(targetName)
      },
      connection() {
      // 建立連線物件
        this.socket = new SockJS(`http://xxxxxx:8089/ws`);//連線服務端提供的通訊介面,連線以後才可以訂閱廣播訊息和個人訊息
        // 獲取STOMP子協議的客戶端物件
        this.stompClient = Stomp.over(this.socket);
        // 定義客戶端的認證資訊,按需求配置
        var headers = {
          login: `mylogin`,
          passcode: `mypasscode`,
          // additional header
          `client-id`: `my-client-id`
        };
        // 向伺服器發起websocket連線
        this.stompClient.connect(headers,(frame) => {
          this.stompClient.subscribe(`/topic/chat_msg`, (msg) => { // 訂閱服務端提供的某個topic
           consolel.log(msg.body);  // msg.body存放的是服務端傳送給我們的資訊
          });
        }, (err) => {
            // 連線發生錯誤時的處理函式
            console.log(err);
        });

      },
      // 斷開連線
      disconnect() {
        if (this.stompClient != null) {
          this.stompClient.disconnect();
          console.log("Disconnected");
        }
      }
    }
};
複製程式碼

結語

不知道我是否有寫明白,我才疏學淺,表達能力有限,如果有不明白的地方,可傳送疑問到我的郵箱2510909248@qq.com,另外如果有什麼好的意見或者建議,也歡迎騷擾~~~

參考連結

websocket:支援 前端連線 + 訂閱

SockJS簡單介紹

STOMP 客戶端 API 整理

相關文章