Stomp Over Websocket文檔

前言

前兩天整理了websocket的資料,今天就把上次沒說完的Stomp.js好好說一說~
Stomp Over Webscoket參考文檔:http://jmesnil.net/stomp-webs...
本文爲參考文檔的部分翻譯,技術不佳,若有失誤請指正。
本文轉載自我的博客:http://lsxj615.com/2016/08/17...javascript

什麼是Stomp

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,簡單(流)文本定向消息協議,它提供了一個可互操做的鏈接格式,容許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。STOMP協議因爲設計簡單,易於開發客戶端,所以在多種語言和多種平臺上獲得普遍地應用。

協議支持

該庫支持多種版本的STOMP協議:html

下載STOMP.JS

你能夠下載 stomp.js 並在你本身的WEB應用程序中使用。
提供了多種版本也能夠直接用於生產。
這個js文件由CoffeeScript文件構建,請查看Contribute部分下載源碼或瀏覽 annote source codejava

服務端要求

這個庫不是單純的Stomp 客戶端。它旨在WebSockets上運行而不是TCP。基本上,WebSocket協議須要在瀏覽器客戶端和服務端之間進行握手,確保瀏覽器的「same-origin」(同源)安全模型仍然有效。node

這意味着該庫不能鏈接常規的STOMP代理,由於Websocket初始化的握手不是STOMP協議的一部分,他們不能理解從而會拒絕鏈接。git

有一些正在進行的工做添加了WebSocket支持STOMP代理,從而他們能夠在WebSocket協議上接受STOMP鏈接。github

HornetQ

HornetQ是由Red Hat and JBoss創立的開源消息系統.web

要使HornetQ支持STOMP Over WebSocket,下載最新版本並按照下列步驟執行:apache

$ cd hornetq-x.y.z/examples/jms/stomp-websockets
$ mvn clean install
...
INFO: HQ221020: Started Netty Acceptor version 3.6.2.Final-c0d783c         localhost:61614 for STOMP_WS protocol
Apr 15, 2013 1:15:33 PM org.hornetq.core.server.impl.HornetQServerImpl$SharedStoreLiveActivation run
INFO: HQ221007: Server is now live
Apr 15, 2013 1:15:33 PM org.hornetq.core.server.impl.HornetQServerImpl start
INFO: HQ221001: HornetQ Server version 2.3.0.CR2 (black'n'yellow2, 123) [c9e29e45-a5bd-11e2-976a-b3fef7ceb5df]

此時HornetQ已經開啓了,而且61614在端口監聽STOMP over WebSocket
它從URL爲ws://localhost:61614/stomp 接受WebSocket的鏈接。npm

配置文檔數組

ActiveMQ

配置文檔

ActiveMQ Apollo

配置文檔

RabbitMQ

配置文檔

Stilts & Torquebox

Stilts 是一個STOMP原生的消息框架。

TorqueBox 使用Stilts去提供它的Websockets and STOMP stack

Stomp API

STOMP 幀(Frame)

STOMP Over WebSocket 提供了一個直接從Stomp Frame映射到 Javascript 對象的方式。
Stomp Frame幀格式以下:

Property Type Notes
command String name of the frame ("CONNECT", "SEND", etc.)
headers JavaScript object
body String

commandheaders屬性始終會被定義,不過當這個frame沒有頭部時,headers能夠爲空。若這個frame沒有bodybody的值能夠爲null

建立STOMP客戶端

在web瀏覽器中使用普通的Web Socket

STOMP javascript 客戶端會使用ws://的URL與STOMP 服務端進行交互。

爲了建立一個STOMP客戶端js對象,你須要使用Stomp.client(url),而這個URL鏈接着服務端的WebSocket的代理:

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

Stomp.client(url, protocols)也能夠用來覆蓋默認的subprotocols。第二個參數能夠是一個字符串或一個字符串數組去指定多個subprotocols

在web瀏覽器中使用定製的WebSocket

瀏覽器提供了不一樣的WebSocket的協議,一些老的瀏覽器不支持WebSocket的腳本或者使用別的名字。默認下,stomp.js會使用瀏覽器原生的WebSocket class去建立WebSocket。

可是利用Stomp.over(ws)這個方法可使用其餘類型的WebSockets。這個方法獲得一個知足WebSocket定義的對象。

例如,可使用由SockJS實現的Websocket:

<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
    // use SockJS implementation instead of the browser's native implementation
    var ws = new SockJS(url);
    var client = Stomp.over(ws);
    [...]
</script>

若是使用原生的Websockets就使用Stomp.client(url),若是須要使用其餘類型的Websocket(例如由SockJS包裝的Websocket)就使用Stomp.over(ws)

除了初始化有差異,Stomp API在這兩種方式下是相同的。

node.js程序中

經過stompjs npm package一樣也能夠在node.js程序中使用這個庫。

$ npm install stompjs

在node.jsapp中, require這個模塊:

var Stomp = require('stompjs');

爲了與創建在TCP socket的STOMP-broker鏈接,使用Stomp.overTCP(host, port)方法。

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

爲了與創建在Web Socket的STOMP broker鏈接,使用Stomp.overWS(url)方法。

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

除了初始化不一樣,不管是瀏覽器仍是node.js環境下,Stomp API都是相同的。

鏈接服務端

一旦Stomp 客戶端創建了,必須調用它的connect()方法去鏈接,從而Stomp服務端進行驗證。這個方法須要兩個參數,用戶的登陸和密碼憑證。

這種狀況下,客戶端會使用Websocket打開鏈接,併發送一個CONNECT frame

這個鏈接是異步進行的:你不能保證當這個方法返回時是有效鏈接的。爲了知道鏈接的結果,你須要一個回調函數。

var connect_callback = function() {
    // called back after the client is connected and authenticated to the STOMP server
};

可是若是鏈接失敗會發生什麼呢?connect()方法接受一個可選的參數(error_callback),當客戶端不能鏈接上服務端時,這個回調函數error_callback會被調用,該函數的參數爲對應的錯誤對象。

var error_callback = function(error) {
    // display the error's message header:
    alert(error.headers.message);
};

在大多數狀況下,connect()方法可接受不一樣數量的參數來提供簡單的API:

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

loginpasscode是strings,connectCallbackerrorCallback則是functions。(有些brokers(代理)還須要傳遞一個host(String類型)參數。)

若是你須要附加一個headers頭部,connect方法還接受其餘兩種形式的參數:

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

headermap形式,connectCallbackerrorCallback爲functions。

須要注意:若是你使用上述這種方式,你須要自行在headers添加login,passcode(甚至host):

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

斷開鏈接時,調用disconnect方法,這個方法也是異步的,當斷開成功後會接收一個額外的回調函數的參數。以下所示。

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

當客戶端與服務端斷開鏈接,就不會再發送或接收消息了。

Heart-beating

若是STOMP broker(代理)接收STOMP 1.1版本的幀,heart-beating是默認啓用的。heart-beating也就是頻率,incoming是接收頻率,outgoing是發送頻率。

經過改變incomingoutgoing能夠更改客戶端的heart-beating(默認爲10000ms):

client.heartbeat.outgoing = 20000; 
// client will send heartbeats every 20000ms
client.heartbeat.incoming = 0;
// client does not want to receive heartbeats
// from the server

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

發送消息

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

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

client會發送一個STOMP發送幀給/queue/test,這個幀包含一個設置了priority爲9的header和內容爲「Hello, STOMP」的body

若是你想發送一個有body的信息,也必須傳遞headers參數。若是沒有headers須要傳遞,那麼就傳{}便可,以下所示:

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

訂閱(Subscribe)和接收(receive)消息

爲了在瀏覽器中接收消息,STOMP客戶端必須先訂閱一個目的地destination

你可使用subscribe()去訂閱。這個方法有2個必需的參數:目的地(destination),回調函數(callback);還有一個可選的參數headers。其中destination是String類型,對應目的地,回調函數是伴隨着一個參數的function類型。

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

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

默認狀況下,若是沒有在headers額外添加,這個庫會默認構建一個獨一無二的ID。在傳遞headers這個參數時,可使用你本身的ID:

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

這個客戶端會向服務端發送一個STOMP訂閱幀(SUBSCRIBE frame)並註冊回調事件。每次服務端向客戶端發送消息時,客戶端都會輪流調用回調函數,參數爲對應消息的STOMP幀對象(Frame object)。以下所示:

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參數用來標識附加的頭部。

var headers = {ack: 'client', 'selector': "location = 'Europe'"};

client.subscribe("/queue/test", message_callback, headers);

這個客戶端指定了它會確認接收的信息,只接收符合這個selector : location = 'Europe'的消息。

若是想讓客戶端訂閱多個目的地,你能夠在接收全部信息的時候調用相同的回調函數:

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)

若是要停止接收消息,客戶端能夠在subscribe()返回的object對象調用unsubscribe()來結束接收。

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

...

subscription.unsubscribe();

支持JSON

STOMP消息的body必須爲字符串。若是你須要發送/接收JSON對象,你可使用JSON.stringify()JSON.parse()去轉換JSON對象。

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);
};

Acknowledgment(確認)

默認狀況,在消息發送給客戶端以前,服務端會自動確認(acknowledged)。

客戶端能夠選擇經過訂閱一個目的地時設置一個ack headerclientclient-individual來處理消息確認。

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

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

ack()接受headers參數用來附加確認消息。例如,將消息做爲事務(transaction)的一部分,當要求接收消息時其實代理(broker)已經將ACK STOMP frame處理了。

var tx = client.begin();
message.ack({ transaction: tx.id, receipt: 'my-receipt' });
tx.commit();

nack()也能夠用來通知STOMP 1.1.brokers(代理):客戶端不能消費這個消息。與ack()方法的參數相同。

事務(Transactions)

能夠在將消息的發送和確認接收放在一個事務中。

客戶端調用自身的begin()方法就能夠開始啓動事務了,begin()有一個可選的參數transaction,一個惟一的可標識事務的字符串。若是沒有傳遞這個參數,那麼庫會自動構建一個。

這個方法會返回一個object。這個對象有一個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()方法發送消息的時候忘記添加transction header,那麼這不會稱爲事務的一部分,這個消息會直接發送,不會等到事務完成後才發送。

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

調試(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");
};

默認狀況,debug消息會被記錄在在瀏覽器的控制檯。

相關文章
相關標籤/搜索