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

Подключение STOMP-клиента к брокеру поверх WebSocket проходит через несколько уровней: установление WebSocket-соединения, STOMP handshake (CONNECT frame), согласование протокола и подтверждение сессии. Сбой может возникнуть на любом этапе, и диагностика зависит от того, на каком уровне произошла ошибка.

Ошибки подключения условно делятся на несколько категорий: транспортные (WebSocket), протокольные (STOMP), серверные (broker-side), а также ошибки жизненного цикла соединения (таймауты, heartbeat, разрывы сети).


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

WebSocket — базовый транспорт для STOMP.js. Если соединение не установлено, STOMP даже не переходит к отправке CONNECT frame.

Частые причины

  • неверный URL (ws:// или wss://)
  • недоступность сервера
  • блокировка прокси или firewall
  • TLS ошибки при использовании wss://
  • CORS-политики (в браузерной среде)
  • закрытие соединения сервером до handshake

Типичные события

На уровне STOMP.js WebSocket ошибки проявляются через события:

  • onWebSocketError
  • onWebSocketClose

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

import { Client } from "@stomp/stompjs";

const client = new Client({
  brokerURL: "ws://localhost:15674/ws",
  debug: (msg) => console.log(msg),

  onWebSocketError: (event) => {
    console.error("WebSocket error", event);
  },

  onWebSocketClose: (event) => {
    console.warn("WebSocket closed", event.code, event.reason);
  },
});

client.activate();

Коды закрытия соединения

  • 1000 — нормальное закрытие
  • 1006 — аварийное завершение (часто сеть)
  • 1011 — серверная ошибка
  • 1015 — TLS handshake failure

Код 1006 наиболее проблемный, так как не содержит причины на уровне протокола.


Ошибки STOMP CONNECT handshake

После установления WebSocket STOMP отправляет frame:

CONNECT
accept-version:1.2
host:broker

\0

Если сервер отклоняет соединение, подключение не завершается.

Причины отказа

  • неверные credentials
  • отсутствие прав доступа
  • неподдерживаемая версия STOMP
  • неправильный header host
  • лимиты брокера

Обработка STOMP ошибок

STOMP.js предоставляет callback:

  • onStompError

Пример:

const client = new Client({
  brokerURL: "ws://localhost:15674/ws",

  connectHeaders: {
    login: "user",
    passcode: "password",
  },

  onStompError: (frame) => {
    console.error("Broker error:", frame.headers["message"]);
    console.error("Details:", frame.body);
  },
});

Формат ERROR frame

Сервер может вернуть:

ERROR
message:Authentication failed
content-type:text/plain

Access denied

Ошибка содержит:

  • headers (message, version, content-type)
  • body (описание причины)

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

Наиболее частый сценарий при использовании брокеров (RabbitMQ, ActiveMQ, Apollo):

Примеры причин

  • неверный login/passcode
  • отсутствие прав на destination (/queue, /topic)
  • ограничения virtual host
  • expired token (JWT/OAuth)

Поведение клиента

При ошибке аутентификации:

  • WebSocket может оставаться открытым
  • STOMP получает ERROR frame
  • соединение считается невалидным

Heartbeat и разрывы соединения

STOMP поддерживает heartbeat механизм:

heart-beat:10000,10000

Первое число — интервал отправки клиента, второе — сервера.

Проблемы heartbeat

  • сервер не отправляет heartbeat
  • клиент не отправляет heartbeat
  • NAT/прокси разрывает idle соединение
  • event loop блокирует отправку

Симптомы

  • соединение “зависает”
  • отсутствуют сообщения ERROR
  • происходит silent disconnect
  • через некоторое время WebSocket close

Конфигурация STOMP.js

const client = new Client({
  brokerURL: "ws://localhost:15674/ws",
  heartbeatIncoming: 10000,
  heartbeatOutgoing: 10000,
});

При нарушении heartbeat STOMP.js инициирует reconnection (если включено).


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

Подключение может зависнуть на этапе CONNECT.

Причины

  • брокер перегружен
  • сетевые задержки
  • отсутствует ответ на CONNECT frame
  • блокировка на уровне reverse proxy

Поведение STOMP.js

Без дополнительных настроек соединение может оставаться в состоянии CONNECTING.

Решение через reconnectDelay

const client = new Client({
  brokerURL: "ws://localhost:15674/ws",
  reconnectDelay: 5000,
});

Ошибки CORS и WebSocket handshake

В браузере WebSocket handshake подчиняется CORS-подобным ограничениям.

Типичные проблемы

  • отсутствует разрешение Upgrade headers
  • сервер не поддерживает Origin
  • reverse proxy не проксирует /ws endpoint
  • неправильная конфигурация Nginx/Apache

Симптомы

  • WebSocket не открывается
  • ошибка без тела сообщения
  • только onWebSocketError вызывается

Ошибки брокера и закрытие соединения

Брокер может принудительно закрыть соединение:

Причины

  • превышение лимита клиентов
  • idle timeout
  • ошибка маршрутизации сообщений
  • внутренний сбой очереди

Поведение клиента

  • вызывается onWebSocketClose
  • STOMP session становится невалидной
  • возможен auto-reconnect

Обработка ошибок в @stomp/stompjs

Основные callbacks клиента:

  • onWebSocketError
  • onWebSocketClose
  • onStompError
  • onDisconnect
  • onConnect

Комплексная обработка

const client = new Client({
  brokerURL: "ws://localhost:15674/ws",

  reconnectDelay: 3000,

  onConnect: () => {
    console.log("Connected");
  },

  onStompError: (frame) => {
    console.error("STOMP error", frame.body);
  },

  onWebSocketError: (event) => {
    console.error("WS error", event);
  },

  onWebSocketClose: (event) => {
    console.warn("WS closed", event.code);
  },
});

Поведение reconnect и ошибки повторного подключения

Автоматическое переподключение является ключевым механизмом устойчивости.

Алгоритм STOMP.js

  • обнаружение disconnect
  • ожидание reconnectDelay
  • повторный WebSocket handshake
  • повторный CONNECT frame

Проблемные сценарии

  • бесконечный reconnect loop
  • отсутствие backoff стратегии
  • повторная авторизация с устаревшим токеном
  • race condition при быстрых reconnect

Экспоненциальный backoff при ошибках

При нестабильной сети фиксированный reconnectDelay неэффективен.

Реализуется стратегия увеличения задержки:

let delay = 1000;

function getNextDelay() {
  delay = Math.min(delay * 2, 30000);
  return delay;
}

Использование в STOMP.js:

const client = new Client({
  brokerURL: "ws://localhost:15674/ws",
  reconnectDelay: 0,

  onWebSocketClose: () => {
    setTimeout(() => {
      client.activate();
    }, getNextDelay());
  },
});

Ошибки из-за неправильной конфигурации брокера

Некорректные настройки сервера часто проявляются как “необъяснимые” ошибки подключения.

Типовые ошибки

  • отсутствует STOMP plugin
  • выключен WebSocket endpoint
  • неверный path (/ws vs /stomp)
  • mismatch версии STOMP (1.0 vs 1.2)
  • отключенный virtual host

Диагностика через debug режим

STOMP.js предоставляет механизм трассировки:

const client = new Client({
  brokerURL: "ws://localhost:15674/ws",
  debug: (str) => {
    console.log(new Date().toISOString(), str);
  },
});

Что фиксируется

  • отправка CONNECT
  • получение CONNECTED
  • ERROR frames
  • heartbeat events
  • reconnect attempts

Типовые цепочки ошибок

Сценарий 1: неверный URL

WebSocket error → close 1006 → reconnect loop

Сценарий 2: authentication failure

WebSocket open → CONNECT → ERROR frame → disconnect

Сценарий 3: heartbeat timeout

CONNECTED → idle → no heartbeat → close 1006

Сценарий 4: broker overload

CONNECT → delay → no response → timeout → reconnect


Практическая модель обработки ошибок

Устойчивое подключение требует разделения логики:

  • транспортный уровень (WebSocket)
  • протокольный уровень (STOMP)
  • бизнес-уровень (subscription recovery)

При разрыве соединения требуется:

  • восстановление session
  • повторная подписка
  • проверка актуальности токенов
  • контроль дубликатов сообщений