Соединение с брокером в STOMP.js завершается моментом получения
серверного кадра CONNECTED, после которого клиент переходит
в активное состояние и получает возможность отправлять сообщения,
подписываться на очереди и участвовать в обмене данными. Обработка этого
этапа является центральной точкой управления жизненным циклом клиента,
так как именно здесь формируется контекст сессии и инициализируются
прикладные подписки.
Успешное подключение фиксируется после выполнения STOMP handshake
поверх транспортного уровня (обычно WebSocket или SockJS) и получения
кадра протокола STOMP с командой CONNECTED. На этом этапе
библиотека завершает внутреннюю инициализацию и вызывает callback,
связанный с событием подключения.
В STOMP.js это реализуется через параметр onConnect (в
новых версиях клиента) или через обработчик, передаваемый в метод
activate().
Ключевая особенность заключается в том, что никакие операции протокола STOMP не должны выполняться до момента вызова этого обработчика. Любая попытка отправки сообщений или подписки до подключения приведёт к ошибкам или буферизации, зависящей от конфигурации клиента.
Функция обработки подключения получает два основных параметра:
frame — объект STOMP-фрейма CONNECTEDclient-контекст уже активирован, но доступ к нему
осуществляется через текущий экземплярФрейм содержит метаданные соединения:
session — идентификатор сессии на стороне брокераserver — информация о сервере STOMP (если
предоставляется)heart-beat — параметры heartbeat, согласованные между
клиентом и серверомСовременный STOMP.js использует модель активации клиента:
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:8080/ws',
reconnectDelay: 5000,
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000,
onConnect: (frame) => {
console.log('Подключение установлено');
console.log('Session ID:', frame.headers['session']);
}
});
client.activate();
В момент вызова onConnect гарантируется, что транспорт
уже установлен, STOMP handshake завершён и клиент находится в состоянии
OPEN.
Одним из ключевых элементов успешного подключения является
session-id. Он используется для:
Доступ к заголовкам осуществляется через
frame.headers:
onConnect: (frame) => {
const sessionId = frame.headers['session'];
const server = frame.headers['server'];
console.log(sessionId);
console.log(server);
}
Важно учитывать, что набор заголовков не стандартизирован полностью и может отличаться в зависимости от брокера.
Наиболее типичный сценарий в обработчике успешного подключения — регистрация подписок. STOMP требует, чтобы подписки создавались только после установления соединения, так как каждая подписка привязывается к активной сессии.
onConnect: (frame) => {
client.subscribe('/topic/messages', (message) => {
console.log('Получено сообщение:', message.body);
});
};
Подписка, созданная внутри onConnect, гарантированно
привязана к активному session и будет корректно
восстановлена при переподключении (если включена соответствующая логика
клиента).
Во время установления соединения клиент и сервер договариваются о параметрах heartbeat. Это влияет на стабильность соединения и контроль его жизнеспособности.
STOMP.js обрабатывает это автоматически, однако значение heartbeat можно получить косвенно через конфигурацию клиента или серверные заголовки.
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000
Если сервер отклоняет предложенные значения, итоговая конфигурация
согласуется в CONNECTED frame.
После вызова onConnect клиент переходит в устойчивое
состояние, в котором доступны операции:
publish() — отправка сообщенийsubscribe() — подписка на очереди и топикиunsubscribe() — отмена подписокВнутренне клиент STOMP.js переходит из состояния
CONNECTING в OPEN, что фиксируется в состоянии
машины клиента.
При включённом reconnectDelay успешное подключение может
происходить многократно в течение жизненного цикла приложения. В таких
случаях onConnect вызывается каждый раз заново, что требует
идемпотентной инициализации подписок.
Типичная ошибка — дублирование подписок при каждом реконнекте. Это происходит, если не хранить ссылки на подписки:
let subscription;
onConnect: () => {
if (!subscription) {
subscription = client.subscribe('/topic/messages', handler);
}
}
Более корректный подход — очистка старых подписок при переподключении или использование централизованного менеджера подписок.
Хотя обработка ошибок относится к другому этапу жизненного цикла,
важно учитывать, что успешное подключение может сменяться разрывом без
предварительного уведомления. Поэтому обработчик onConnect
часто используется совместно с:
onStompError — ошибки протоколаonWebSocketClose — закрытие транспортного уровняonWebSocketError — ошибки соединения WebSocketТакой подход позволяет строить устойчивую модель реактивного подключения, где успешное соединение является не конечным состоянием, а началом активного цикла взаимодействия.
После успешного подключения обычно выполняется инициализация прикладного слоя:
Пример:
onConnect: (frame) => {
client.publish({
destination: '/app/init',
body: JSON.stringify({ type: 'INIT' })
});
client.subscribe('/topic/state', handlerState);
};
Такая схема делает CONNECTED точкой входа в всю
событийную модель приложения.
При нестабильном соединении onConnect может вызываться
многократно с короткими интервалами. В таких условиях критически
важно:
STOMP.js не гарантирует автоматическую дедупликацию логики приложения, поэтому контроль идемпотентности ложится на прикладной уровень.
Хотя STOMP работает поверх WebSocket или SockJS, успешное подключение STOMP не означает стабильность транспортного уровня. Возможны ситуации, когда:
Поэтому обработчик успешного подключения следует рассматривать как точку синхронизации состояния, а не как гарантию долгосрочной стабильности канала.