Using StompJs v5+

9 minute read

You can find samples at https://github.com/stomp-js/samples/.

The STOMP Broker

Ensure that your STOMP broker supports STOMP over WebSockets. While some messaging brokers support it out of the box, a few may need additional configuration or activating plugins.

Include stompjs

This npm distribution has a UMD package and ES6 modules. The web browsers will use the UMD via a script tag, and Node’s require and ES import will use the appropriate versions.

Polyfills

Important: before using, please check Polyfills & Critical Dependencies.

In Web Browser

In NodeJS

See Polyfills & Critical Dependencies for installing dependencies.

// For StompJs >= 5.1.0
StompJs = require('@stomp/stompjs');

// For StompJs 5.0.x
StompJs = require('@stomp/stompjs/esm5');

Read along to learn how to use the StompJs object.

TypeScript or ES6

See Polyfills & Critical Dependencies for installing dependencies.

These libraries have been developed using typescript, and the typings are included in the distribution.

You can import classes like the following:

import { Client, Message } from '@stomp/stompjs';

You can use these classes without prefixing with StompJs..

There is no StompJs class/object to be imported.

Setting/getting options

All options can be set/get by directly operating on the client instance:

const client = new StompJs.Client();
client.brokerURL = 'ws://localhost:15674/ws';

console.log(client.brokerURL);

These can also be set passing key/value pairs to Client constructor or to Client#configure.

Create a STOMP client

STOMP JavaScript clients will communicate to a STOMP server using a ws:// or wss:// URL.

const client = new StompJs.Client({
  brokerURL: 'ws://localhost:15674/ws',
  connectHeaders: {
    login: 'user',
    passcode: 'password',
  },
  debug: function (str) {
    console.log(str);
  },
  reconnectDelay: 5000,
  heartbeatIncoming: 4000,
  heartbeatOutgoing: 4000,
});

client.onConnect = function (frame) {
  // Do something, all subscribes must be done is this callback
  // This is needed because this will be executed after a (re)connect
};

client.onStompError = function (frame) {
  // Will be invoked in case of error encountered at Broker
  // Bad login/passcode typically will cause an error
  // Complaint brokers will set `message` header with a brief message. Body may contain details.
  // Compliant brokers will terminate the connection after any error
  console.log('Broker reported error: ' + frame.headers['message']);
  console.log('Additional details: ' + frame.body);
};

client.activate();

To deactivate a client call Client#deactivate. It will stop attempting to reconnect and disconnect if there is an active connection.

client.deactivate();

Send messages

When the client is connected to the server, it can send STOMP messages using the Client#publish method.

client.publish({ destination: '/topic/general', body: 'Hello world' });

// There is an option to skip content length header
client.publish({
  destination: '/topic/general',
  body: 'Hello world',
  skipContentLengthHeader: true,
});

// Additional headers
client.publish({
  destination: '/topic/general',
  body: 'Hello world',
  headers: { priority: '9' },
});

Starting version 5, sending binary messages is supported. To send a binary message body, use the binaryBody parameter. It should be a Uint8Array.

const binaryData = generateBinaryData(); // This need to be of type Uint8Array
// setting content-type header is not mandatory, however a good practice
client.publish({
  destination: '/topic/special',
  binaryBody: binaryData,
  headers: { 'content-type': 'application/octet-stream' },
});

Subscribe and receive messages

The STOMP client must first subscribe to a destination to receive messages.

To subscribe to a destination, you can use the Client#subscribe method. The method takes two mandatory arguments: destination, a String corresponding to the destination and callback, a function with one message argument and an optional argument headers, a JavaScript object for additional headers.

const subscription = client.subscribe('/queue/test', callback);

The subscribe() method returns an object with one attribute, id, that correspond to the client subscription ID and one method unsubscribe() that can be used later on to unsubscribe the client from this destination.

Every time the broker sends a message to the client, the client will, in turn, invoke the callback with a Message 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');
  }
};

The subscribe() method takes an optional headers argument to specify additional headers when subscribing to a destination:

const headers = { ack: 'client' };
client.subscribe('/queue/test', message_callback, headers);

The client specifies that it will handle the message acknowledgment.

To stop receiving messages, the client can use the unsubscribe method on the object returned by the Client#subscribe method.

const subscription = client.subscribe('queue/test', onmessage);

// ... use the subscription ...

subscription.unsubscribe();

Binary messages

Prepare your broker

Not every broker will support binary messages out of the box. For example, RabbitMQ (see: https://www.rabbitmq.com/web-stomp.html) will need the following to be added to the server configuration:

web_stomp.ws_frame = binary

Publishing binary messages

Use parameter binaryBody of Client#publish to send binary data of type Uint8Array.

See Send messages for an example.

Receiving binary messages

The library does not guess whether the incoming data is text/binary. To access the message body as a string, please use Message#body and to access it as binary, please use Message#binaryBody.

There is no generally accepted convention in STOMP (actually messaging in general) to indicate binary messages. Therefore, the message senders and receivers must agree on the required convention. For example, you may choose to set a content-type header to indicate a binary message.

// within message callback
if (message.headers['content-type'] === 'application/octet-stream') {
  // message is binary
  // call message.binaryBody
} else {
  // message is text
  // call message.body
}

JSON support

The body of a STOMP message must be a String or a Uint8Array. If you want to send and receive JSON objects, you can use JSON.stringify() andJSON.parse() to transform the JSON object to a String and vice versa.

const quote = { symbol: 'AAPL', value: 195.46 };
client.publish({
  destination: '/topic/stocks',
  body: JSON.stringify(quote),
});

client.subscribe('/topic/stocks', function (message) {
  const quote = JSON.parse(message.body);
  alert(quote.symbol + ' is at ' + quote.value);
});

Acknowledgment

By default, the server will automatically acknowledge STOMP messages before the message is delivered to the client.

Instead, the client can choose to handle message acknowledgment by subscribing to a destination with the ack header set to client or client-individual.

In that case, the client must use the Message#ack method to inform the broker that it has processed the message.

const subscription = client.subscribe(
  '/queue/test',
  function (message) {
    // do something with the message
    // ...
    // and acknowledge it
    message.ack();
  },
  { ack: 'client' }
);

The Message#ack method accepts headers argument for additional headers. For example, to acknowledge a message as part of a transaction and request a receipt:

const tx = client.begin();
message.ack({ transaction: tx.id, receipt: 'my-receipt' });
tx.commit();

The client should Message#nack to inform STOMP 1.1 or higher brokers that the client did not consume the message. It takes the same arguments as the Message#ack method.

Transactions

Messages can be sent and acknowledged in a transaction.

The client starts a transaction using the Client#begin method, which takes an optional transaction_id.

This method returns an object with an id attribute corresponding to the transaction ID and two methods:

The client can then send and acknowledge messages in the transaction by specifying a transaction indetified by the transaction id.

// start the transaction
const tx = client.begin();
// send the message in a transaction
client.publish({
  destination: '/queue/test',
  headers: { transaction: tx.id },
  body: 'message in a transaction',
});
// commit the transaction to effectively send the message
tx.commit();

If you forget to add the transaction header when calling Client#publish, the message will not be part of the transaction, and it will be sent directly without waiting for the completion of the transaction.

// start the transaction
const tx = client.begin();
// oops! send the message outside the transaction
client.publish({
  destination: '/queue/test',
  body: 'message in a transaction',
});
tx.abort(); // Too late! the message has been sent

Heart-beating

For a connection with STOMP protocol 1.1 or higher, heart-beating is enabled by default. Options Client#heartbeatIncoming and Client#heartbeatOutgoing can be used to control heart-beating (default value for both is 10,000ms). The client can disable heart beating by setting these to 0.

client.heartbeatOutgoing = 20000; // client will send heartbeats every 20000ms
client.heartbeatIncoming = 0; // client does not want to receive heartbeats
// from the server

Auto Reconnect

The client supports automatic reconnecting in case of a connection failure. It is controlled by a option Client#reconnectDelay. The default value is 5000ms, which indicates that an attempt to connect will be made 5000ms after a connection drop.

// Add the following if you need automatic reconnect (delay is in milliseconds)
client.reconnectDelay = 300;

You can set the reconnectDelay to quite a small value.

Debug

On a busy system volume of logs can be overwhelming. Therefore, by default, the debug messages are ignored.

Client#debug property can be set to a function (which will receive a String argument) to enable debug statements:

client.debug = function (str) {
  console.log(str);
};

Usually, headers of the incoming and outgoing frames are logged. Set Client#logRawCommunication to log entire frames.

Callbacks

Lifecycle callbacks

  • Client#beforeConnect - invoked each time before connection to STOMP broker is attempted. You can modify connection parameters and other callbacks. On v6+ you can set an async function for this callback.
  • Client#onConnect - invoked for each time STOMP broker connects and STOMP handshake is complete.
  • Client#onDisconnect - invoked after each graceful disconnection. If the connection breaks because of an error or network failure, it will not be called.
  • Client#onStompError - invoked when the broker reports an Error.
  • Client#onWebSocketClose - when the WebSocket closes. It is the most reliable way of knowing that the connection has terminated.

Frame callbacks

  • Client#onUnhandledMessage - typically brokers will send messages corresponding to subscriptions. However, brokers may support concepts beyond the standard definition of STOMP - for example, RabbitMQ supports concepts of temporary queues. This callback will be invoked if any message is received that is not linked to a subscription.
  • Client#onUnhandledReceipt - you should prefer Client#watchForReceipt. If there is any incoming receipt for which there is no active watcher, this callback will be invoked.
  • Client#onUnhandledFrame - it will be invoked if broker sends a non standard STOMP Frame.

Advanced notes

Version 5+ of this library has taken significant variation from the previous syntax.

It is possible to alter configuration options and callbacks. New values will take effect as soon as possible. For example:

The callback sequences are arranged in a way that most expected operations should work. For example, it is possible to call Client#deactivate within Client#onStompError or Client#onWebSocketClose.

The above also allows adjusting Client#reconnectDelay in Client#onWebSocketClose. You can implement exponential back-off using a series of such adjustments.

Even Client#brokerURL or Client#connectHeaders can be altered which would get used in a subsequent reconnect.

Updated: