什么是STOMP?
STOMP是一种简单的面向文本的消息传递协议。它定义了一种可互操作的有线格式, 以便任何可用的STOMP客户端都可以与任何STOMP消息代理进行通信,以在各种语言和平台之间提供简单而广泛的消息互操作性(STOMP网站上有STOMP客户端和服务器实现的列表。
什么是WebSocket API?
WebSockets是“用于Web的TCP”。
当Google宣布在Chrome浏览器中提供 WebSocket时,它解释了WebSockets背后的想法:
WebSocket API使Web应用程序能够以直接的方式处理与服务器端进程的双向通信。开发人员已经将XMLHttpRequest(“ XHR”)用于此类目的,但是XHR使开发与服务器进行来回通信的Web应用程序变得不必要地复杂。XHR基本上是异步HTTP,并且由于您需要使用诸如长期悬挂的GET这样的棘手技术来将数据从服务器发送到浏览器,因此简单的任务会迅速变得复杂。与XMLHttpRequest相反,WebSockets在您的浏览器中提供了一个真正的双向通信通道。一旦获得WebSocket连接,就可以通过调用send()方法从浏览器向服务器发送数据,并通过onmessage事件处理程序从服务器向浏览器接收数据。
除了新的WebSocket API外,浏览器还用于与服务器进行通信的新协议(“ WebSocket协议”)。该协议不是原始TCP,因为它需要提供浏览器的“同源”安全模型。它也不是HTTP,因为WebSocket流量不同于HTTP的请求-响应模型。使用新的WebSocket协议的WebSocket通信应使用较少的带宽,因为与一系列XHR和悬挂的GET不同,一旦建立了单个连接,就不会交换任何标头。要使用此新的API和协议并利用更简单的编程模型和更有效的网络流量,您确实需要与之通信的新服务器实现。
该API是HTML5的一部分,并且大多数现代Web浏览器(包括Mac OS X和iOS上的Google Chrome,Firefox和Safari)都支持(不同程度...)。
协议支持
该库支持多种版本的STOMP协议:
服务器要求
该库不是纯STOMP客户端。它旨在在非TCP的WebSockets协议上运行。基本上,WebSocket协议要求浏览器的客户端和服务器之间进行握手,以确保浏览器的“同源”安全模型保持有效。
这意味着该库无法连接到常规STOMP代理,因为它们不了解由WebSocket发起的握手,该握手不是STOMP协议的一部分,并且可能会拒绝连接。
目前正在进行将WebSocket支持添加到STOMP代理的工作,以便他们将通过WebSocket协议接受STOMP连接。
大黄蜂
HornetQ是Red Hat和JBoss开发的开源消息传递系统。
要使用支持通过WebSocket的STOMP来启动HornetQ,请下载最新版本并运行以下步骤:
$ cd hornetq-x.y.z/examples/jms/stomp-websockets$ mvn clean install... INFO:HQ221020:启动了Netty Acceptor版本3.6.2,用于STOMP_WS协议的Final-c0d783c localhost:61614 2013年4月15日,下午1:15:33 org.hornetq.core.server.impl.HornetQServerImpl $ SharedStoreLiveActivation运行 INFO:HQ221007:服务器现在处于活动状态 2013年4月15日,下午1:15:33 org.hornetq.core.server.impl.HornetQServerImpl开始 信息:HQ221001:HornetQ Server版本2.3.0.CR2(black‘n‘yellow2,123)[c9e29e45-a5bd-11e2-976a-b3fef7ceb5df]
HornetQ现在已启动,并通过端口上的WebSocket监听STOMP 61614
。
它接受来自URL的WebSocket连接ws://localhost:61614/stomp
要在启用了STOMP Over WebSocket的情况下配置和运行HornetQ,请按照 说明进行操作。
ActiveMQ
ActiveMQ是Apache开发的开源消息传递系统。从5.4快照开始,ActiveMQ支持STOMP Over WebSocket。
要在启用了STOMP Over WebSocket的情况下配置和运行ActiveMQ,请按照 说明进行操作。
ActiveMQ阿波罗
ActiveMQ Apollo是下一代ActiveMQ代理。从一开始,Apollo就支持STOMP Over WebSocket。
要在启用了STOMP Over WebSocket的情况下配置和运行Apollo,请按照 说明进行操作。
兔子MQ
RabbitMQ是VMware赞助的开源消息传递系统。
要在启用了STOMP Over WebSocket的情况下配置和运行RabbitMQ,请按照说明安装Web-Stomp插件。
高跷和扭矩箱
Stilts是一个STOMP本地消息传递框架,旨在解决将STOMP视为消息传递的主要合同,并围绕它进行集成,而不是简单地将STOMP填充应用于现有服务。
TorqueBox使用Stilts项目提供其WebSockets和STOMP堆栈。
下载stomp.js JavaScript文件
您可以下载stomp.js以便在您的Web应用程序中使用它
一个精缩版,还提供了生产中使用。
该JavaScript文件是从CoffeeScript文件生成的。请参阅“贡献”部分以下载源代码或浏览带注释的源代码。
STOMP API
脚架
WebSocket上的STOMP提供了从STOMP框架到JavaScript对象的直接映射。
财产 | 类型 | 笔记 |
---|---|---|
command |
细绳 |
该帧的名称("CONNECT" ,"SEND" 等)
|
headers |
JavaScript对象 | |
body |
细绳 |
的command
和headers
特性将总是被限定,但headers
如果该帧不具有报头可以是空的。该body
可null
如果框架没有一个机构。
创建一个STOMP客户端
在具有常规Web套接字的Web浏览器中
STOMP JavaScript客户端将使用ws://
URL与STOMP服务器进行通信。
要创建STOMP客户端JavaScript对象,您需要Stomp.client(url)
使用与服务器的WebSocket端点相对应的URL进行调用:
var url = "ws://localhost:61614/stomp";
var client = Stomp.client(url);
的Stomp.client(url, protocols)
也可用于覆盖由库提供的默认子协议:[‘v10.stomp‘, ‘v11.stomp]‘
(对于STOMP 1.0 1.1规范)。第二个参数可以是单个字符串,也可以是字符串数组,以指定多个子协议。
在带有自定义WebSocket的Web浏览器中
Web浏览器支持WebSocket协议的不同版本。一些较旧的浏览器不提供WebSocket JavaScript或以其他名称公开它。默认情况下,stomp.js
将使用Web浏览器本机WebSocket
类创建WebSocket。
但是,可以通过使用该Stomp.over(ws)
方法来使用其他类型的WebSocket 。此方法需要一个符合WebSocket定义的对象。
例如,可以使用SockJS项目提供的实现,而该实现可以使用各种特定于浏览器的传输协议来代替:
<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>
使用Stomp.client(url)
使用普通的WebSockets或使用Stomp.over(ws)
,如果你需要另一种类型的WebSocket的。
除了此初始化之外,两种情况下的STOMP API均相同。
在node.js应用程序中
通过使用stompjs npm包,该库也可以在node.js应用程序中使用 。
$ npm install stompjs
在node.js应用程序中,要求模块具有:
var Stomp = require(‘stompjs‘);
要通过TCP套接字连接到STOMP代理,请使用以下Stomp.overTCP(host, port)
方法:
var client = Stomp.overTCP(‘localhost‘, 61613);
要通过Web Socket连接到STOMP代理,请改用以下Stomp.overWS(url)
方法:
var client = Stomp.overWS(‘ws://localhost:61614/stomp‘);
除了此初始化之外,无论STOMP API是在Web浏览器中还是在node.js应用程序中运行,都保持不变。
连接到服务器
创建STOMP客户端后,它必须调用其connect()
方法以有效连接并验证STOMP服务器。该方法采用两个强制性参数, login
并且passcode
与用户凭据相对应。
在后台,客户端将使用WebSocket打开连接并发送CONNECT框架。
连接是异步完成的:您无法保证在调用connect
返回时被有效连接。要通知连接,您需要将一个connect_callback
函数传递 给connect()
方法:
var connect_callback = function() {
// called back after the client is connected and authenticated to the STOMP server
};
但是,如果连接失败怎么办?该connect()
方法接受一个可选error_callback
参数,如果客户端无法连接到服务器,则该参数将被调用。回调将使用单个参数调用,该参数是与STOMP ERROR帧相对应的错误对象 :
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);
其中login
,passcode
是字符串,connectCallback
并且errorCallback
是函数(某些代理还要求传递主机字符串)。
connect()
如果您需要传递其他标头,则该方法还接受其他两个变体:
client.connect(headers, connectCallback);
client.connect(headers, connectCallback, errorCallback);
哪里header
是地图,connectCallback
并且errorCallback
是函数。
请注意,如果您使用这些形式,则必须自己添加login
,passcode
(并最终添加host
)标题:
var headers = {
login: ‘mylogin‘,
passcode: ‘mypasscode‘,
// additional header
‘client-id‘: ‘my-client-id‘
};
client.connect(headers, connectCallback);
要断开客户端与服务器的连接,可以调用其disconnect()
方法。断开连接是异步的:断开连接有效时会收到通知,该disconnect
方法采用可选callback
参数。
client.disconnect(function() {
alert("See you next time!");
};
客户端断开连接后,它将不再能够发送或接收消息。
心脏跳动
如果STOMP代理接受STOMP 1.1帧,则默认情况下会启用心跳。
该client
对象具有一个heartbeat
字段,可通过更改其字段incoming
和outgoing
整数字段来配置心跳(两个字段的默认值为10000
ms):
client.heartbeat.outgoing = 20000; // client will send heartbeats every 20000ms
client.heartbeat.incoming = 0; // client does not want to receive heartbeats
// from the server
心跳window.setInterval()
用于定期发送心跳和/或检查服务器心跳。
发送信息
当客户端连接到服务器时,它可以使用该send()
方法发送STOMP消息。该方法采用destination
与STOMP目的地相对应的强制性参数。它还具有两个可选参数:headers
,一个包含其他消息头的JavaScript对象,和body
一个String对象。
client.send("/queue/test", {priority: 9}, "Hello, STOMP");
客户端将向目的地发送STOMP SEND帧/queue/test
,其标头priority
设置为9
和正文Hello, STOMP
。
如果要发送带有正文的消息,则还必须传递headers
参数。如果没有要传递的标头,请使用空的JavaScript文字{}
:
client.send(destination, {}, body);
订阅和接收消息
要在浏览器中接收消息,STOMP客户端必须首先订阅目标。
您可以使用该subscribe()
方法订阅目的地。该方法具有2个强制参数:destination
,对应于目的地的String和 callback
,具有一个message
参数和可选参数的函数headers
,用于附加标头的JavaScript对象。
var subscription = client.subscribe("/queue/test", callback);
这些subscribe()
方法返回一个具有1属性的JavaScript对象id
,该属性与客户端订阅ID相对应,并且是一种unsubscribe()
可以稍后用于从此目的地退订客户端的方法。
默认情况下,如果标头中未提供唯一的ID,则库将生成唯一的ID。要使用您自己的ID,请使用headers
参数传递它:
var mysubid = ‘...‘;
var subscription = client.subscribe(destination, callback, { id: mysubid });
客户端将向服务器发送STOMP SUBSCRIBE帧并注册回调。每次服务器向客户端发送消息时,客户端将依次使用与消息相对应的STOMP Frame对象调用回调:
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);
客户端指定它将处理消息确认,并且有兴趣仅接收与选择器匹配的消息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);
要停止接收消息,客户端可以在该unsubscribe()
方法返回的对象上使用该subscribe()
方法。
var subscription = client.subscribe(...);
...
subscription.unsubscribe();
JSON支持
STOMP消息的正文必须为String
。如果要发送和接收 JSON对象,则可以使用JSON.stringify()
和JSON.parse()
将JSON对象转换为String,反之亦然。
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);
};
致谢
默认情况下,STOMP消息将在被传递到客户端之前由服务器自动确认。
客户端可以选择订阅目的地并选择设置为或的标头来处理消息确认。ack
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‘}
);
该ack()
方法接受headers
用于其他标头的参数以确认消息。例如,当ACK
代理有效地处理了STOMP帧时,可以确认消息是交易的一部分,并要求收据:
var tx = client.begin();
message.ack({ transaction: tx.id, receipt: ‘my-receipt‘ });
tx.commit();
该nack()
方法也可以用于通知STOMP 1.1经纪人,客户端并不会消耗该消息。它采用与ack()
方法相同的参数。
交易次数
可以在事务中发送和确认消息。
事务由客户端使用其begin()
方法来启动,该方法采用一个可选transaction
的String来唯一标识该事务。如果没有transaction
通过,该库将自动生成一个。
此方法返回一个JavaScript对象,该对象具有与id
事务ID对应的属性和两个方法:
-
commit()
提交交易 -
abort()
中止交易
然后,客户端可以通过指定交易transaction
集来发送和/或确认交易中的消息 id
。
// 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();
如果您transaction
在调用时忘记添加标头,则send()
该消息将不属于事务,并且将直接发送,而无需等待事务完成。
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
属性设置为带有String
参数的函数,以查看该库的所有调试语句:
client.debug = function(str) {
// append the debug log to a #debug div somewhere in the page using JQuery:
$("#debug").append(str + "\n");
};
默认情况下,调试消息记录在浏览器窗口的控制台中。
例子
源代码中包含一个聊天示例 examples/chat/index.html
您需要启动一个支持WebSocket的STOMP服务器(例如使用HornetQ)。
单击Connect按钮以连接到服务器并订阅/queue/test/
队列。
然后,您可以在页面底部的表单中键入消息,以将STOMP消息发送到队列。客户收到的消息将显示在页面顶部。
您还可以发送常规的STOMP消息,并在浏览器中看到它们。例如,直接telnet在STOMP默认端口上使用:
$ telnet localhost 61613 CONNECT login:guest passcode:guest ^@ 连接的 会话:1092296064
^@是一个空(control-@以ASCII为单位)字节。
SEND destination:/queue/test Hello from TCP! ^@
您现在应该已经在浏览器中收到此消息。