Библиотека STOMP.js поддерживает несколько способов подключения к брокеру сообщений. Конкретный механизм зависит от архитектуры приложения, сетевой инфраструктуры, требований к отказоустойчивости и используемого транспорта.
Основой работы библиотеки является протокол STOMP поверх WebSocket. Клиент устанавливает WebSocket-соединение, после чего начинает обмен STOMP-фреймами:
CONNECTCONNECTEDSENDSUBSCRIBEMESSAGEACKDISCONNECTПодключение — это центральный этап жизненного цикла клиента. Ошибки на этом этапе приводят к невозможности подписки, отправки сообщений и синхронизации состояния.
Современные версии библиотеки используют класс
Client.
import { Client } from '@stomp/stompjs';
const client = new Client();
После создания экземпляра задаются параметры подключения:
client.brokerURL = 'ws://localhost:15674/ws';
Или:
const client = new Client({
brokerURL: 'ws://localhost:15674/ws'
});
Свойство brokerURL является наиболее простым методом
подключения.
const client = new Client({
brokerURL: 'ws://localhost:15674/ws'
});
client.activate();
Внутри библиотеки автоматически создаётся объект
WebSocket.
Подключение может выполняться через:
ws:// — обычный WebSocket;wss:// — защищённый WebSocket через TLS.Пример защищённого подключения:
const client = new Client({
brokerURL: 'wss://broker.example.com/ws'
});
Защищённый транспорт обязателен:
Современные браузеры блокируют ws://, если страница
открыта через HTTPS.
После конфигурирования клиента вызывается метод:
client.activate();
Этот метод:
CONNECT;CONNECTED.До вызова activate() соединение не устанавливается.
Для отслеживания успешного подключения используется
onConnect.
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
console.log('Connected');
}
});
После подключения обычно:
STOMP позволяет передавать дополнительные заголовки.
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: {
login: 'admin',
passcode: 'admin'
}
});
Эти данные помещаются во фрейм:
CONNECT
login:admin
passcode:admin
Во многих современных системах используются JWT-токены.
const token = localStorage.getItem('token');
const client = new Client({
brokerURL: 'wss://api.example.com/ws',
connectHeaders: {
Authorization: `Bearer ${token}`
}
});
Некоторые брокеры анализируют заголовки STOMP, а некоторые — HTTP-заголовки WebSocket handshake.
Если требуется полный контроль над WebSocket, используется
webSocketFactory.
const client = new Client({
webSocketFactory: () => {
return new WebSocket('ws://localhost:8080/ws');
}
});
Этот механизм особенно важен:
new Client({
brokerURL: 'ws://localhost/ws'
});
Особенности:
new Client({
webSocketFactory: () => new WebSocket(url)
});
Особенности:
Некоторые серверы работают через SockJS.
Для этого используется библиотека SockJS.
import SockJS from 'sockjs-client';
import { Client } from '@stomp/stompjs';
const client = new Client({
webSocketFactory: () => {
return new SockJS('http://localhost:8080/stomp');
}
});
SockJS предоставляет fallback-механизмы:
SockJS полезен:
В современных системах предпочтительнее чистый WebSocket.
В Node.js отсутствует встроенный WebSocket API браузера.
Используется пакет ws.
import { Client } from '@stomp/stompjs';
import WebSocket from 'ws';
const client = new Client({
webSocketFactory: () => {
return new WebSocket('ws://localhost:15674/ws');
}
});
STOMP.js поддерживает автоматическое переподключение.
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
reconnectDelay: 5000
});
Если соединение разрывается, библиотека повторит подключение через 5 секунд.
После потери соединения библиотека:
reconnectDelay;const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
reconnectDelay: 0
});
В этом случае переподключение отключается полностью.
В production-системах фиксированный reconnect может создавать перегрузку брокера.
Часто реализуется экспоненциальная задержка:
let reconnectTime = 1000;
const client = new Client({
webSocketFactory: () => {
return new WebSocket('ws://localhost:15674/ws');
},
reconnectDelay: reconnectTime,
onWebSocketClose: () => {
reconnectTime = Math.min(reconnectTime * 2, 30000);
},
onConnect: () => {
reconnectTime = 1000;
}
});
STOMP поддерживает heartbeat-пакеты.
Настройка:
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
heartbeatIncoming: 4000,
heartbeatOutgoing: 4000
});
Клиент и сервер периодически отправляют служебные символы.
Если heartbeat перестаёт приходить:
Частота отправки heartbeat клиентом.
heartbeatOutgoing: 4000
Ожидаемая частота heartbeat от сервера.
heartbeatIncoming: 4000
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
heartbeatIncoming: 0,
heartbeatOutgoing: 0
});
Обычно heartbeat отключают:
Для диагностики используются обработчики:
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onStompError: (frame) => {
console.error(frame.headers['message']);
},
onWebSocketError: (event) => {
console.error(event);
}
});
Срабатывает при транспортных ошибках:
Срабатывает при ошибках протокола STOMP:
Для логирования используется:
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
debug: (message) => {
console.log(message);
}
});
STOMP.js начинает выводить:
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'wss://broker.example.com/ws',
connectHeaders: {
login: 'admin',
passcode: 'admin'
},
reconnectDelay: 5000,
heartbeatIncoming: 4000,
heartbeatOutgoing: 4000,
debug: (str) => {
console.log(str);
},
onConnect: () => {
console.log('Connected');
client.subscribe('/topic/news', (message) => {
console.log(message.body);
});
client.publish({
destination: '/app/chat',
body: JSON.stringify({
text: 'Hello'
})
});
},
onStompError: (frame) => {
console.error(frame.headers['message']);
},
onWebSocketError: (event) => {
console.error(event);
}
});
client.activate();
Для корректного закрытия соединения используется:
client.deactivate();
Метод:
DISCONNECT;Метод возвращает Promise.
await client.deactivate();
Это особенно важно:
Свойство:
client.connected
Пример:
if (client.connected) {
console.log('Connected');
}
Иногда требуется анализировать внутреннее состояние сокета.
client.webSocket.readyState
Возможные значения:
| Состояние | Значение |
|---|---|
| CONNECTING | 0 |
| OPEN | 1 |
| CLOSING | 2 |
| CLOSED | 3 |
В корпоративных сетях WebSocket может проходить через reverse proxy:
Критически важны:
location /ws {
proxy_pass http://localhost:15674;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_read_timeout 86400;
}
Для RabbitMQ обычно используется Web STOMP plugin.
Типичный URL:
ws://localhost:15674/ws
Необходимо включить:
rabbitmq-plugins enable rabbitmq_web_stomp
ActiveMQ поддерживает STOMP через отдельный transport connector.
Пример конфигурации:
<transportConnector
name="stomp"
uri="stomp://0.0.0.0:61613"/>
WebSocket transport:
<transportConnector
name="websocket"
uri="ws://0.0.0.0:61614"/>
Иногда подключение откладывается до первого действия пользователя.
let initialized = false;
function connect() {
if (!initialized) {
client.activate();
initialized = true;
}
}
Подход снижает:
В SPA-приложениях обычно используется единый экземпляр клиента.
class StompService {
constructor() {
this.client = new Client({
brokerURL: 'ws://localhost:15674/ws'
});
}
connect() {
this.client.activate();
}
}
export default new StompService();
Такой подход предотвращает:
После deactivate() допускается повторный запуск:
await client.deactivate();
client.activate();
STOMP.js создаст новый WebSocket и начнёт новый цикл подключения.
brokerURL: 'http://localhost/ws'
Ошибка:
SyntaxError: Failed to construct 'WebSocket'
Должно использоваться:
ws://
или:
wss://
Ошибка:
Mixed Content: blocked
Причина:
ws://.Решение:
wss://
Ошибка:
WebSocket connection failed
Причины:
После сетевого сбоя клиент остаётся отключённым.
Причина:
reconnectDelay: 0
Причины:
const client = new Client({
brokerURL: 'wss://broker.example.com/ws',
reconnectDelay: 5000,
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000,
connectHeaders: {
Authorization: `Bearer ${token}`
},
debug: () => {}
});
Особенности: