前端vue使用stomp.js、sock.js完成websocket
Sock.js
Sock.js 是一個JavaScript庫,為了應對很多瀏覽器不支持websocket協議問題。SockJ會自動對應websocket,如果websocket不可用,就會自動降為輪訓的方式。
Stomp.js
STOMP-Simple Text Oriented Message Protocol-面向消息的簡單文本協議。Sockjs為websocket提供了備選方案,但是通信形式層級過低。Stompjs則增加了語義
WebSocket、SockJs、STOMP三者關系
WebSocket 是底層協議,SockJS 是WebSocket 的備選方案,也是底層協議,而 STOMP 是基於 WebSocket(SockJS)的上層協議。
-
HTTP協議解決了 web 瀏覽器發起請求以及 web 服務器響應請求的細節,假設 HTTP 協議 並不存在,只能使用 TCP 套接字來 編寫 web 應用。
-
直接使用 WebSocket(SockJS) 就很類似於 使用 TCP 套接字來編寫 web 應用,因為沒有高層協議,就需要我們定義應用間所發送消息的語義,還需要確保連接的兩端都能遵循這些語義;
-
同HTTP在TCP 套接字上添加請求-響應模型層一樣,STOMP在WebSocket 之上提供了一個基於幀的線路格式層,用來定義消息語義;
實例
<template>
<div>
<p>
<button @click="send('1')">1分鍾</button>
<button @click="send('2')">10分鍾</button>
<button @click="send('3')">1小時</button>
<button @click="send('4')">24小時</button>
</p>
<ul>
<li v-for="(item,index) in tableData" :key="index">{{ item.name }}:{{ item.value }}</li>
</ul>
</div>
</template>
<script>
import Stomp from 'stompjs'
import SockJS from 'sockjs-client'
// const headers = {}
const headers = {
login: 'mylogin',
passcode: 'mypasscode',
// additional header
'client-id': 'my-client-id',
Author: '1235465tyrgw32rsgg'
};
export default {
data () {
return {
socketUrl: '/websocket/ws', // ws://localhost:8080/websocket/ws
tableData: [],
reconnecting: false,
socket: null,
stompClient: null
}
},
mounted () {
this.initWebsocket()
},
beforeDestroy() {
this.closeSocket()
},
methods: {
/* 只需要在連接服務器注冊端點endPoint時,寫訪問服務器的全路徑URL:
new SockJS('http://127.0.0.1:9091/sbjm-cheng/endpointOyzc');
其他監聽指定服務器廣播的URL不需要寫全路徑
stompClient.subscribe('/topic/getResponse',function(response){})
*/
/* 創建stompClient: (1) 使用原生的websocket (2) 使用定制的websocket(例如sockjs包裹的websocket)
① Stomp.client("ws://localhost:61614/stomp")
② SockJS的url是http、https協議,而不是 ws
const socket = new SockJS("http://127.0.0.1:9091/sbjm-cheng/endpointOyzc");
Stomp.over(socket)
const ws = new Websocket("ws://localhost:61614/ws")
Stomp.over(ws)
*/
initWebsocket () {
/*
① 創建sockJS對象;
② 創建stomp客戶端
③ stompClient客戶端 連接 stomp服務器
*/
this.socket = new SockJS(this.socketUrl)
this.stompClient = Stomp.over(this.socket)
this.stompClient.connect(
headers, // headers頭部信息。可添加客戶端的認證信息。也可以不添加信息,headers 直接就設置為 {}
frame => {
// 連接成功: 訂閱服務器的地址。為了瀏覽器可以接收到消息,必須先訂閱服務器的地址
this.connectSucceed()
}, err => {
// 連接失敗的回調
this.reconnect(this.socketUrl, this.connectSucceed)
})
},
/* 連接成功的回調:訂閱服務器的地址。為了瀏覽器可以接收到消息,必須先訂閱服務器的地址 */
connectSucceed () {
// 設置心跳發送接受頻率(ms)默認為10000ms。 heart-beating是利用window.setInterval()去規律地發送heart-beats或者檢查服務端的heart-beats。
this.stompClient.heartbeat.outgoing = 10000
this.stompClient.heartbeat.incoming = 0
this.stompClient.subscribe('/topic/dashboard/data', res => {
this.tableData = res.body.list
})
/*
當客戶端與服務端連接成功后,可以調用 send()來發送STOMP消息。這個方法必須有一個參數,用來描述對應的STOMP的目的地。
另外可以有兩個可選的參數:headers,object類型包含額外的信息頭部;body,一個String類型的參數。
client.send("/queue/test", {priority: 9}, "Hello, STOMP");
// client會發送一個STOMP發送幀給/queue/test,這個幀包含一個設置了priority為9的header和內容為“Hello, STOMP”的body。
*/
this.stompClient.send('/topic/dashboard/send',{}, '1')
},
reconnect (socketUrl, callback) {
this.reconnecting = true
let connected = false
const timer = setInterval(() => {
this.socket = new SockJS(socketUrl)
this.stompClient = Stomp.over(this.socket)
this.stompClient.connect(headers, frame => {
this.reconnectting = false
connected = true
clearInterval(timer)
callback()
}, err => {
console.log('Reconnect failed!');
if(!connected) console.log(err);
})
}, 1000);
},
closeSocket(){
if(this.stompClient != null){
this.stompClient.disconnect()
// this.stompClient.disconnect(()=>{
// console.log('連接關閉')
// });
}
},
send(flag){
this.stompCLient.send('/topic/dashboard/send',{}, flag)
}
},
}
</script>