WebSocket子協議STOMP詳解 頂 原

1. STOMP簡介

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,它是一個簡單的文本消息傳輸協議,提供了一個可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。STOMP協議由於設計簡單,易於開發客戶端,因此在多種語言和多種平臺上得到廣泛地應用。

2. 協議支持

  • STOMP 1.0
  • STOMP 1.1 (including heart-beating)

3. 下載JavaScript客戶端包文件

stomp.min.js,可直接使用於web項目中

4. STOMP API介紹

4.1 STOMP Frame(幀)

STOMP Over WebSocket 提供了一個直接從 STOMP frame到JavaScript object的映射。

Frame Object

Property

Type

Notes

command

String

name of the frame ("CONNECT", "SEND", etc.)

headers

JavaScript object

 

body

String

 

command和headers屬性始終會被定義,但是當這個frame沒有頭部信息時,headers參數可以爲空,用{}表示。若這個frame沒有body(主體內容),body的值可以爲null。

4.2 STOMP客戶端創建(普通的WebSocket方式)

STOMP JavaScript客戶端將使用URL爲 ws:// 與STOMP server建立通信。

使用 Stomp.client(url) 來創建STOMP客戶端的js對象,如:

var url = "ws://localhost:61614/stomp";
var client = Stomp.client(url);

使用Stomp.client(url, protocols)可以覆蓋默認的subprotocols,如protocols爲['v10.stomp','v11.stomp'] 基於STOMP 1.0 & 1.1規範,第二個參數可以爲單獨的一個String類型,也可以爲一個String的數組類型。

4.3 STOMP客戶端創建(自定義WebSocket方式)

web瀏覽器支持不同的WebSocket協議版本,但是一些老版本的瀏覽器不支持WebSocket方式創建的js腳本,可以使用stomp.js,stomp.js會使用瀏覽器原生的WebSocket class來創建WebSocket。

使用Stomp.over(ws)方法,ws參數可以指定其他類型的WebSocket(如SockJS包裝的WebSocket)

<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
    // 使用SockJS實現而不是瀏覽器的本地實現
    var ws = new SockJS(url);
    var client = Stomp.over(ws);
    [...]
</script>

4.4 在node.js應用中的使用

使用npm安裝stompjs

> npm install stompjs

在node.js程序中通過require導入stompjs模塊

var Stomp = require('stompjs');

建立一個基於TCP socket的連接到STOMP代理

var client = Stomp.overTCP('localhost', 61613);

建立一個基於Web Socket的連接到STOMP代理

var client = Stomp.overWS('ws://localhost:61614/stomp');

除了初始化不同,無論是瀏覽器還是node.js環境下,Stomp API都是相同的。

4.5 連接到服務端

當STOMP client創建好後,通過connect()方法進行與STOMP seerver的連接和認證,connect方法可接受多個參數來提供簡單的API。

client.connect(login, passcode, connectCallback);
client.connect(login, passcode, connectCallback, errorCallback);
client.connect(login, passcode, connectCallback, errorCallback, host);

注:login與passcode是String類型,connectCallback與errorCallback是回調函數,host爲String類型

 如果需要附加一些其他的信息,可以通過傳遞一個headers參數。

client.connect(headers, connectCallback);
client.connect(headers, connectCallback, errorCallback);

注:headers爲map類型, connectCallback與errorCallback爲回調函數

如附加的headers參數

var headers = {
    login: 'mylogin',
    passcode: 'mypasscode',
    // additional header
    'client-id': 'my-client-id'
};
client.connect(headers, connectCallback);

也可使用{}來表示不附加任何headers參數

斷開連接時,調用disconnect方法,這個方法也是異步的,當斷開成功後會接收一個額外的回調函數的參數,如:

client.disconnect(function() {
   alert("See you next time!");
};

當客戶端client斷開連接後,不能再發送和接收任何messages。

4.6 心跳檢測(heart-beating)

如果STOMP 代理接收的幀是STOMP 1.1協議時,默認心跳檢測是開啓的。

客戶端client對象有一個字段 heartbeat ,通過改變incoming和outgoing數值,來配置心跳頻率(默認頻率值爲:10000ms)

client.heartbeat.outgoing = 20000; // 客戶端每20000ms發送一次心跳檢測
client.heartbeat.incoming = 0;     // client不接收serever端的心跳檢測

注:heart-beating是利用window.setInterval()去規律地發送heart-beats或者檢查服務端的heart-beats

4.7 發送消息

當客戶端與服務端連接成功後,可以調用send()方法來發送STOMP消息。這個方法必須有一個參數, 用來描述對應的STOMP的目的地。另外可以有兩個可選的參數:headers,object類型,包含額外的信息頭;body爲一個String類型的參數。

client.send("/queue/test", {priority: 9}, "Hello, STOMP");

代碼解釋:客戶端將發送一個STOMP的幀到 /queue/test 地址的目的地,攜帶的headers參數priority爲9,消息體爲Hello, STOMP

注:如果你想發送一個有消息體(body)的信息,也必須傳遞headers參數。如果沒有headers需要傳遞,可以用{}來表示,如:

client.send(destination, {}, body);

 4.8 訂閱(Subscribe)和接收消息

瀏覽器接收一個消息,STOMP客戶端首先必須訂閱一個目標地址destination。

使用subscribe()方法訂閱,該方法接收兩個必選的參數destination String類型的目的地址和callback回調函數,還有一個可選的參數headers

var subscription = client.subscribe("/queue/test", callback);

subscribe()方法返回一個js對象,這個對象包含一個id屬性,對應這個這個客戶端的訂閱id。而unsubscribe()可以用來取消客戶端對這個目的地destination的訂閱。

默認情況下,如果沒有在headers參數中額外添加,這個庫會默認構建一個唯一的id。在傳遞headers這個參數時,可以使用你自己的id如:

var mysubid = '...';
var subscription = client.subscribe(destination, callback, { id: mysubid });

客戶端發送一個STOMP的訂閱幀到服務端,並註冊一個回調函數,每當服務端發送消息到客戶端時,客戶端都會調用回調函數,回調函數中的參數爲STOMP幀對象。

callback = function(message) {
    // called when the client receives a STOMP message from the server
    if (message.body) {
      alert("got message with body " + message.body)
    } else {
      alert("got empty message");
    }
});

subscribe()方法接收一個可選的參數headers,當訂閱一個目的地destination的時候可以附加該參數

var headers = {ack: 'client', 'selector': "location = 'Europe'"};
client.subscribe("/queue/test", message_callback, headers);

代碼解釋:該客戶端只接收匹配selector location = 'Europe'的消息,並且會確認接收到的message

注:如果想讓客戶端訂閱多個目的地destinations,可以使用同一個回調函數來接收messages

onmessage = function(message) {
    // called every time the client receives a message
}
var sub1 = client.subscribe("queue/test", onmessage);
var sub2 = client.subscribe("queue/another", onmessage);

 調用unsubscribe()方法可以終止接收messages

var subscription = client.subscribe(...);
  
...
  
subscription.unsubscribe();

4.9 JSON的支持

如果想發送和接收JSON對象的消息,可以通過JSON.stringify() 和 JSON.parse()來轉換

var quote = {symbol: 'APPL', value: 195.46};
  client.send("/topic/stocks", {}, JSON.stringify(quote));

  client.subcribe("/topic/stocks", function(message) {
  var quote = JSON.parse(message.body);
  alert(quote.symbol + " is at " + quote.value);
};

4.10 消息確認

默認情況,在消息發送給客戶端之前,服務端會自動確認。

客戶端可以選擇通過訂閱一個目的地destination時設置一個ack,header爲client或client-individual來處理消息確認。

在下面這個例子,客戶端必須調用message.ack()來通知客戶端它已經接收了消息。

var subscription = client.subscribe("/queue/test",
    function(message) {
      // do something with the message
      ...
      // and acknowledge it
      message.ack();
    },
    {ack: 'client'}
);

使用nack()方法可以通知STOMP 1.1 代理,客戶端沒有消費該消息,和ack()方法的參數相同

4.11 事務(Transactions)

消息的發送確認可以在一個事務中處理。

通過調用客戶端自身的begin()方法來啓動事務,該方法有一個可選的參數transaction,String類型,唯一標識一個事務,如果沒有傳遞參數,那麼stompjs庫會自動生成。該方法會返回一個js對象,包含一個id屬性,對應該事務的ID。

另外兩個方法:

  • commit()提交事務
  • abort()終止事務

在一個事務中,客戶端可以在發送/接受消息時指定transaction id來設置transaction。

// start the transaction
var tx = client.begin();
// send the message in a transaction
client.send("/queue/test", {transaction: tx.id}, "message in a transaction");
// commit the transaction to effectively send the message
tx.commit();

注:如果在調用send()方法發送消息時未指定transaction頭信息,則該事務不起作用,如:

var txid = "unique_transaction_identifier";
// start the transaction
var tx = client.begin();
// oops! send the message outside the transaction
client.send("/queue/test", {}, "I thought I was in a transaction!");
tx.abort(); // Too late! the message has been sent

 4.12 Debug調試

有一些測試代碼能有助於你知道庫發送或接收的是什麼,從而來調試程序。

客戶端可以將其debug屬性設置爲一個函數,傳遞一個字符串參數去觀察庫所有的debug語句。

client.debug = function(str) {
    // append the debug log to a #debug div somewhere in the page using JQuery:
    $("#debug").append(str + "\n");
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章