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消息会被记录在在浏览器的控制台。

相关文章
相关标签/搜索