WebSocket进行STOMP

什么是STOMP?

WebSocket进行STOMP

STOMP是一种简单的面向文本的消息传递协议。它定义了一种可互操作的有线格式, 以便任何可用的STOMP客户端都可以与任何STOMP消息代理进行通信,以在各种语言和平台之间提供简单而广泛的消息互操作性(STOMP网站上有STOMP客户端和服务器实现列表

什么是WebSocket API?

WebSocket进行STOMP

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 细绳  

commandheaders特性将总是被限定,但headers如果该帧不具有报头可以是空的。bodynull如果框架没有一个机构。

创建一个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);

其中loginpasscode是字符串,connectCallback并且errorCallback是函数(某些代理还要求传递主机字符串)。

connect()如果您需要传递其他标头,则方法还接受其他两个变体:


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

哪里header是地图,connectCallback并且errorCallback是函数。

请注意,如果您使用这些形式,则必须自己添加loginpasscode(并最终添加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字段,可通过更改其字段incomingoutgoing整数字段来配置心跳(两个字段的默认值为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

心跳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

WebSocket进行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‘

WebSocket进行STOMP

如果要将客户端预订到多个目的地,则可以使用相同的回调来接收所有消息:


  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消息将在被传递到客户端之前由服务器自动确认。

客户端可以选择订阅目的地并选择设置为标头来处理消息确认ackclientclient-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();
WebSocket进行STOMP

如果您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!
  ^@
  

您现在应该已经在浏览器中收到此消息。

WebSocket进行STOMP

上一篇:js-null的使用场景


下一篇:优化 ASP.NET Core Docker 镜像的大小