媒介
前两天整理了websocket
的材料,本日就把上次没说完的Stomp.js
好好说一说~
Stomp Over Webscoket参考文档:http://jmesnil.net/stomp-webs…
本文为参考文档的部份翻译,手艺不佳,若有失误请斧正。
本文转载自个人博客:http://lsxj615.com/2016/08/17…
什么是Stomp
STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简朴(流)文本定向音讯协定,它供应了一个可互操纵的衔接花样,许可STOMP客户端与恣意STOMP音讯代办(Broker)举行交互。STOMP协定由于设想简朴,易于开辟客户端,因此在多种语言和多种平台上获得广泛地运用。
协定支撑
该库支撑多种版本的STOMP协定:
下载STOMP.JS
你能够下载 stomp.js 并在你本身的WEB运用顺序中运用。
供应了多种版本也能够直接用于临盆。
这个js文件由CoffeeScript文件构建,请检察Contribute部份下载源码或阅读 annote source code
服务端请求
这个库不是纯真的Stomp 客户端。它旨在WebSockets上运转而不是TCP。基本上,WebSocket协定须要在阅读器客户端和服务端之间举行握手,确保阅读器的“same-origin”(同源)平安模子依然有用。
这意味着该库不能衔接通例的STOMP代办,由于Websocket初始化的握手不是STOMP协定的一部份,他们不能明白从而会谢绝衔接。
有一些正在举行的事情增加了WebSocket支撑STOMP代办,从而他们能够在WebSocket协定上吸收STOMP衔接。
HornetQ
HornetQ是由Red Hat and JBoss建立的开源音讯体系.
要使HornetQ支撑STOMP Over WebSocket,下载最新版本并按照以下步骤实行:
$ 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的衔接。
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 |
command
和headers
属性一直会被定义,不过当这个frame
没有头部时,headers
能够为空。若这个frame
没有body
,body
的值能够为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);
login
和passcode
是strings,connectCallback
和errorCallback
则是functions。(有些brokers(代办)还须要通报一个host
(String范例)参数。)
假如你须要附加一个headers
头部,connect
要领还吸收其他两种情势的参数:
client.connect(headers, connectCallback);
client.connect(headers, connectCallback, errorCallback);
header
是map
情势,connectCallback
和errorCallback
为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
是发送频次。
经由过程转变incoming
和outgoing
能够变动客户端的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的目的地。别的能够有两个可选的参数:headers
,object
范例包括分外的信息头部;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 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'}
);
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音讯会被纪录在在阅读器的控制台。