STOMP поверх WebSocket изначально предполагает наличие стабильного двунаправленного канала связи. Однако в реальных сетевых условиях WebSocket не всегда доступен: корпоративные прокси, ограниченные мобильные сети, устаревшие браузеры или строгие политики безопасности могут блокировать установку WebSocket-соединения. В таких сценариях используется SockJS как транспортная абстракция, обеспечивающая совместимость через набор fallback-механизмов.
SockJS реализует модель, в которой клиент и сервер взаимодействуют через единый API, но внутри может использовать различные технологии передачи данных: WebSocket, XHR-streaming, XHR-polling, iframe-streaming и другие. Для STOMP.js это означает возможность сохранить единый протокол сообщений при изменяющейся транспортной среде.
STOMP.js не взаимодействует с сетью напрямую — он работает поверх WebSocket-совместимого объекта. SockJS подменяет стандартный WebSocket-клиент, предоставляя интерфейс с аналогичной сигнатурой.
Основная идея интеграции заключается в следующем:
Таким образом, SockJS выступает как адаптер, расширяющий доступность STOMP-коммуникаций.
SockJS проходит несколько стадий установления соединения:
Handshake Клиент отправляет HTTP-запрос для определения доступных транспортов.
Выбор транспорта Сервер и клиент договариваются о наиболее подходящем способе связи:
Установление канала После выбора транспорта SockJS создаёт канал передачи данных, эмулирующий поведение WebSocket.
STOMP.js при этом не осведомлён о внутреннем механизме — он получает объект с интерфейсом send/onmessage/close.
Интеграция выполняется через передачу SockJS-инстанса в STOMP клиент.
import { Client } from '@stomp/stompjs';
import SockJS from 'sockjs-client';
const socketFactory = () => {
return new SockJS('https://example.com/ws');
};
const stompClient = new Client({
webSocketFactory: socketFactory,
reconnectDelay: 5000,
debug: (msg) => {
console.log(msg);
}
});
stompClient.activate();
В данном случае webSocketFactory заменяет стандартный
WebSocket-конструктор, позволяя подставить SockJS как транспорт.
SockJS не является прямой заменой WebSocket, а представляет собой эмуляцию его поведения.
Ключевые отличия:
Для STOMP.js это означает, что логика сообщений остаётся неизменной, но характеристики доставки могут варьироваться.
Для корректной работы SockJS необходим сервер, который поддерживает протокол SockJS. Наиболее распространённый вариант — Spring WebSocket.
Пример конфигурации на сервере:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.withSockJS();
}
}
Ключевой момент — вызов withSockJS(), который активирует
поддержку альтернативных транспортов.
После установления SockJS-канала STOMP работает поверх него без изменений:
STOMP-фреймы не зависят от типа транспорта, что позволяет сохранять совместимость.
stompClient.onConn ect = (frame) => {
stompClient.subscribe('/topic/chat', (message) => {
console.log(JSON.parse(message.body));
});
stompClient.publish({
destination: '/app/chat',
body: JSON.stringify({ text: 'hello' })
});
};
SockJS здесь полностью скрыт, выступая лишь транспортным уровнем.
SockJS совместно с STOMP.js обеспечивает дополнительную устойчивость при потере соединения.
Основные сценарии:
STOMP.js управляет логикой повторного подключения через параметр
reconnectDelay, тогда как SockJS управляет сменой
транспорта внутри себя.
Несмотря на универсальность, SockJS имеет ряд ограничений:
При высоконагруженных системах SockJS часто рассматривается как резервный механизм, а не основной транспорт.
При использовании SockJS важно учитывать параметры клиента STOMP:
reconnectDelay — определяет интервал повторного
подключенияheartbeatIncoming и heartbeatOutgoing —
контроль живости соединенияdebug — диагностика транспортных переходовbeforeConnect — возможность подготовки состояния перед
установкой соединенияconst stompClient = new Client({
webSocketFactory: () => new SockJS('/ws'),
reconnectDelay: 3000,
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000
});
SockJS особенно полезен в следующих условиях:
В системах с контролируемой средой WebSocket обычно предпочтительнее, так как обеспечивает меньшую задержку и более простую архитектуру.
SockJS не влияет на выбор брокера STOMP (RabbitMQ, ActiveMQ, Spring broker relay). Он работает ниже уровня протокола и лишь доставляет байтовый поток.
Типичная цепочка выглядит так:
SockJS транспорт → STOMP кадры → брокер сообщений → обработчики подписок
Разделение ответственности позволяет менять транспорт без изменения бизнес-логики.
SockJS автоматически применяет стратегию деградации:
STOMP.js при этом воспринимает всё как единый канал, не различая внутреннюю реализацию.
SockJS поддерживается большинством серверных платформ, ориентированных на WebSocket:
Однако в современных архитектурах наблюдается тенденция к отказу от SockJS в пользу чистого WebSocket с более продвинутыми retry-механизмами на уровне клиента и инфраструктуры.