Веб-приложения долгое время строились вокруг классической модели HTTP-запросов. Браузер отправляет запрос серверу, сервер возвращает ответ. Такая схема подходит для загрузки страниц, REST API и большинства CRUD-операций, однако плохо работает в системах, где требуется постоянный обмен сообщениями в реальном времени.
Проблемы начинают проявляться в следующих сценариях:
В подобных приложениях серверу необходимо самостоятельно отправлять
данные клиенту сразу после появления событий. Постоянный опрос сервера
через HTTP (polling) создает лишнюю нагрузку, задержки и
неэффективное использование сети.
Для решения этой проблемы появились WebSocket-соединения.
WebSocket предоставляет постоянное двустороннее соединение между браузером и сервером. После установки соединения стороны могут обмениваться данными без повторных HTTP-запросов.
Простейший пример:
const socket = new WebSocket('ws://localhost:8080');
socket.onmess age = (event) => {
console.log(event.data);
};
socket.send('Hello');
Несмотря на простоту, WebSocket работает только на уровне транспорта. Он умеет:
Но WebSocket не определяет:
Каждый проект начинает самостоятельно придумывать собственный протокол поверх WebSocket. В результате возникают проблемы:
Именно здесь появляется STOMP.
STOMP (Simple Text Oriented Messaging Protocol) — текстовый протокол обмена сообщениями поверх TCP или WebSocket.
Главная задача STOMP — превратить низкоуровневое WebSocket-соединение в полноценную систему обмена сообщениями.
STOMP вводит:
Пример STOMP-фрейма:
SEND
destination:/app/chat
Hello World
STOMP делает WebSocket похожим на полноценную messaging-систему.
STOMP.js — JavaScript-библиотека для работы с протоколом STOMP в браузере и Node.js.
Библиотека берет на себя:
Типичный пример подключения:
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:8080/ws'
});
client.onConn ect = () => {
console.log('Connected');
client.subscribe('/topic/messages', (message) => {
console.log(message.body);
});
client.publish({
destination: '/app/chat',
body: 'Hello'
});
};
client.activate();
Без STOMP взаимодействие между клиентом и сервером быстро превращается в хаотичный обмен JSON-строками.
Например:
socket.send(JSON.stringify({
type: 'NEW_MESSAGE',
room: 'general',
text: 'Hello'
}));
Со временем появляется необходимость:
Команды и форматы начинают разрастаться.
STOMP стандартизирует этот процесс.
Вместо ручного анализа type используются:
/topic/queue/appSUBSCRIBESENDACKNACKАрхитектура становится предсказуемой.
Одной из ключевых причин использования STOMP является модель pub/sub (publish-subscribe).
Суть модели:
Пример:
/topic/news
Все подписчики топика получают новые сообщения.
Подписка:
client.subscribe('/topic/news', callback);
Отправка:
client.publish({
destination: '/app/news',
body: 'Breaking News'
});
Такая модель идеально подходит для:
STOMP помогает разделить роли компонентов системы.
Отвечает только за транспорт.
Отвечает за messaging-протокол.
Отвечает за маршрутизацию сообщений.
STOMP почти всегда используется вместе с брокерами сообщений.
Популярные брокеры:
Брокер берет на себя:
STOMP.js выступает клиентом этой системы.
Связка STOMP + WebSocket + Spring стала практически стандартом для Java backend.
Причина в том, что Spring предоставляет готовую инфраструктуру:
@EnableWebSocketMessageBroker
Маршруты:
/app
/topic
/queue
Контроллеры:
@MessageMapping("/chat")
Отправка сообщений:
@SendTo("/topic/messages")
На клиенте STOMP.js подключается практически без дополнительной настройки.
Все клиенты используют одинаковые команды:
Можно заменить backend без переписывания frontend.
Новые разработчики быстрее понимают архитектуру.
STOMP поддерживается множеством брокеров.
Система легче переносится на distributed-инфраструктуру.
client.subscribe('/topic/orders', callback);
client.publish({
destination: '/app/order',
body: JSON.stringify(order)
});
client.publish({
destination: '/app/chat',
headers: {
priority: 'high'
},
body: 'Message'
});
client.subscribe('/queue/tasks', callback, {
ack: 'client'
});
Позволяет отслеживать разрыв соединения.
reconnectDelay: 5000
Frontend-разработчику сложно работать с низкоуровневыми messaging-системами.
Например, AMQP значительно сложнее:
STOMP предоставляет упрощенный интерфейс.
Вместо сложной конфигурации:
client.subscribe('/topic/chat', callback);
Это делает STOMP.js удобным для:
Пользователь отправляет сообщение:
client.publish({
destination: '/app/chat',
body: JSON.stringify(message)
});
Все клиенты получают обновление:
client.subscribe('/topic/messages', callback);
Сервер публикует изменения курса.
Клиенты получают данные мгновенно без обновления страницы.
STOMP часто используется в:
Push-like уведомления внутри веб-приложения:
Например:
Изменения синхронизируются между клиентами в реальном времени.
Когда приложение работает на одном сервере, WebSocket может выглядеть простым.
Но при росте системы появляются проблемы:
STOMP хорошо вписывается в event-driven подход.
Серверы начинают обмениваться событиями через брокер сообщений, а браузеры получают данные через STOMP.js.
Browser
|
WebSocket
|
Custom Protocol
|
Backend
Недостатки:
Browser
|
STOMP.js
|
WebSocket
|
Message Broker
|
Backend Services
Преимущества:
Одной из особенностей STOMP является текстовый формат фреймов.
Пример:
SUBSCRIBE
id:sub-1
destination:/topic/chat
^@
Преимущества текстового формата:
Это особенно полезно при разработке и интеграции.
Socket.IO — популярная альтернатива для realtime-связи.
Однако подходы отличаются.
STOMP чаще применяется в enterprise-системах.
MQTT ориентирован прежде всего на IoT.
Особенности MQTT:
STOMP лучше подходит для веб-приложений и enterprise-backend.
STOMP может быть избыточным для:
Иногда достаточно обычного WebSocket API.
Несмотря на появление новых realtime-технологий, STOMP продолжает активно использоваться благодаря нескольким факторам:
Для крупных систем STOMP остается одним из наиболее удобных способов организации realtime-взаимодействия между браузером, backend-сервисами и message broker-инфраструктурой.