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客户端包文件
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");
};