Обработка ошибок подключения

Подключение STOMP-клиента к брокеру сообщений является многоэтапным процессом, зависящим от транспортного уровня (WebSocket или SockJS), конфигурации брокера, сетевых условий и корректности параметров клиента. Ошибки могут возникать как на этапе установления соединения, так и после его успешного создания.

На уровне STOMP.js подключение обычно инициируется через Client.activate(), после чего библиотека пытается установить транспортное соединение и выполнить STOMP handshake. Любое отклонение на этом пути приводит к переходу клиента в состояние ошибки или повторного подключения.

Ключевые источники проблем:

  • недоступность WebSocket-эндпоинта
  • некорректный URL брокера
  • несовместимость версий STOMP и брокера
  • ошибки CORS при использовании SockJS
  • сбои сети или нестабильное соединение
  • отклонение подключения сервером (authentication / authorization)

Жизненный цикл ошибки подключения

STOMP.js управляет состоянием соединения через внутреннюю машину состояний. Ошибка может возникнуть на разных этапах:

  1. Инициализация транспортного соединения
  2. WebSocket handshake
  3. STOMP CONNECT frame
  4. Ответ брокера (CONNECTED / ERROR frame)

Каждый этап генерирует разные типы ошибок, которые отражаются через callbacks onStompError, onWebSocketError, а также события onDisconnect.


Ошибки WebSocket уровня

WebSocket-ошибки возникают до того, как STOMP-протокол начинает обмен кадрами. Они связаны с транспортом и сетевым уровнем.

Типичные сценарии:

  • DNS-ошибка при разрешении домена брокера
  • TCP connection refused
  • закрытый порт на сервере
  • прокси или firewall блокирует upgrade-запрос
  • неправильный протокол ws/wss

STOMP.js обрабатывает такие ситуации через событие:

client.onWebSocketEr ror = (event) => {
  console.error('WebSocket error', event);
};

Важно учитывать, что WebSocket-ошибка не содержит STOMP-контекста, так как STOMP-сессия ещё не установлена.


Ошибки STOMP handshake

После установления WebSocket соединения клиент отправляет STOMP frame CONNECT. На этом этапе возможны логические ошибки протокола.

Основные причины:

  • неверный login / passcode
  • отсутствие обязательных headers
  • несовместимость версий протокола (например, сервер поддерживает 1.0, а клиент использует 1.2)
  • брокер отклоняет соединение по политике безопасности

Пример обработки:

client.onStompEr ror = (frame) => {
  console.error('Broker error:', frame.headers['message']);
  console.error('Details:', frame.body);
};

STOMP ERROR frame содержит:

  • message — краткое описание
  • version — версия протокола (иногда)
  • body — расширенная информация от брокера

Ошибки авторизации и аутентификации

Многие брокеры (RabbitMQ, ActiveMQ, Spring STOMP endpoints) требуют авторизацию на этапе CONNECT.

Ошибки проявляются как:

  • отказ в подключении с кодом 401 / 403
  • STOMP ERROR frame с сообщением AUTH FAILED
  • мгновенное закрытие WebSocket после handshake

Типичная проблема — передача заголовков в неправильном формате:

client.connectHeaders = {
  login: 'user',
  passcode: 'password'
};

Некоторые серверы требуют кастомные headers:

  • Authorization
  • JWT токены
  • sessionId

При их отсутствии соединение может быть формально установлено на уровне WebSocket, но STOMP-сессия будет немедленно разорвана.


Ошибки CORS и SockJS

При использовании SockJS транспорт проходит через HTTP fallback механизмы. В этом случае добавляется слой браузерной политики CORS.

Основные проблемы:

  • отсутствие Access-Control-Allow-Origin
  • запрет методов OPTIONS / POST
  • несовпадение домена фронтенда и брокера
  • некорректная настройка credentials

SockJS может маскировать ошибку как “transport failure”, хотя первопричина находится на уровне HTTP.


Повторные подключения и обработка нестабильных соединений

STOMP.js поддерживает автоматический механизм переподключения через reconnectDelay. Ошибки соединения не всегда являются критическими и могут быть временными.

const client = new Client({
  brokerURL: 'wss://example.com/ws',
  reconnectDelay: 5000
});

Поведение при ошибках:

  • временный сбой → автоматический reconnect
  • длительный сбой → бесконечные попытки (если не ограничено)
  • критическая ошибка handshake → отключение без повторов (в зависимости от брокера)

Контроль состояния осуществляется через:

  • onWebSocketClose
  • onDisconnect
  • внутренний таймер reconnect

Закрытие соединения с ошибкой

Закрытие WebSocket может происходить как инициировано сервером, так и клиентом. Коды закрытия помогают определить причину:

  • 1000 — нормальное завершение
  • 1006 — неожиданное закрытие
  • 1002 — протокольная ошибка
  • 1011 — серверная ошибка

STOMP.js не всегда раскрывает код напрямую, поэтому диагностика часто требует логирования уровня транспорта.


Логирование и диагностика

Эффективная обработка ошибок невозможна без детального логирования всех этапов подключения.

Рекомендуемая стратегия:

  • логирование WebSocket событий (open, error, close)
  • логирование STOMP frame lifecycle
  • сохранение raw frames CONNECT / ERROR
  • фиксация временных меток подключения

Пример расширенного логирования:

client.debug = (str) => {
  console.log('[STOMP]', str);
};

При необходимости анализа сетевых проблем полезно включать DevTools Network WebSocket inspection для просмотра frame-level обмена.


Состояния клиента при ошибках

Внутреннее состояние Client изменяется в зависимости от типа ошибки:

  • CONNECTING — попытка установления соединения
  • CONNECTED — успешное подключение
  • RECONNECTING — попытка восстановления
  • DISCONNECTED — завершённое состояние
  • CLOSING — инициировано закрытие

Ошибки могут переводить клиент в разные состояния без явного уведомления через API, если не реализованы обработчики событий.


Особенности ошибок при использовании брокеров Spring и RabbitMQ

Spring WebSocket STOMP endpoints:

  • часто требуют /ws endpoint конфигурации
  • могут отклонять CONNECT при отсутствии handshake headers
  • поддерживают user destination, влияющие на авторизацию

RabbitMQ STOMP plugin:

  • чувствителен к версии STOMP (1.1 / 1.2)
  • может закрывать соединение при некорректных heart-beats
  • возвращает ERROR frame с диагностикой канала

Ошибки heartbeat и их влияние на соединение

Heartbeat механизм влияет на устойчивость соединения. При его некорректной настройке возможны скрытые разрывы.

Сценарии:

  • клиент отправляет heartbeat, сервер не поддерживает → disconnect
  • сервер требует heartbeat, клиент не отправляет → timeout
  • несоответствие интервалов → ложные disconnect события

Heartbeat ошибки часто интерпретируются как сетевые сбои, хотя являются логической ошибкой конфигурации.


Таймауты подключения

Отсутствие ответа от сервера в разумный промежуток времени приводит к таймауту транспортного уровня.

Причины:

  • перегруженный брокер
  • медленный TLS handshake
  • блокировка промежуточными прокси
  • неправильный endpoint

STOMP.js не всегда предоставляет отдельное событие таймаута, поэтому оно проявляется как WebSocket close без error frame.


Стратегии устойчивого подключения

Устойчивость к ошибкам достигается комбинацией нескольких механизмов:

  • экспоненциальный backoff при reconnect
  • ограничение числа попыток переподключения
  • разделение транспортных и STOMP ошибок
  • централизованная обработка событий клиента
  • контроль состояния снаружи STOMP.js

Поведение клиента при нестабильной сети определяется не только библиотекой, но и архитектурой приложения, в котором она используется.