Отправка текстовых данных

Отправка текстовых данных в STOMP.js выполняется через метод publish(). Этот метод формирует STOMP-фрейм SEND и передаёт его брокеру сообщений.

Базовый пример:

client.publish({
    destination: '/topic/chat',
    body: 'Привет, сервер!'
});

После вызова библиотека формирует примерно такой STOMP-фрейм:

SEND
destination:/topic/chat
content-length:16

Привет, сервер!

Ключевым параметром является destination — адрес назначения сообщения. Именно туда брокер направляет переданные данные.


Основная структура отправки

Метод publish() принимает объект с параметрами.

Стандартная структура:

client.publish({
    destination: '/topic/messages',
    headers: {},
    body: '',
    binaryBody: null,
    skipContentLengthHeader: false
});

На практике чаще всего используются только:

client.publish({
    destination: '/topic/messages',
    body: 'Текст сообщения'
});

Параметр destination

Поле destination определяет канал, очередь или маршрут доставки.

Примеры:

destination: '/topic/news'
destination: '/queue/tasks'
destination: '/app/chat'

Назначение зависит от конфигурации брокера:

Префикс Назначение
/topic/ Публикация в топик
/queue/ Очередь сообщений
/app/ Маршрутизация на серверное приложение
/exchange/ RabbitMQ exchange
/user/ Персональные сообщения

Передача текстового содержимого

Текст сообщения передаётся через поле body.

Пример:

client.publish({
    destination: '/topic/chat',
    body: 'Новое сообщение'
});

STOMP.js автоматически преобразует строку в текстовый payload.


Отправка многострочного текста

STOMP поддерживает многострочные сообщения без дополнительных настроек.

Пример:

client.publish({
    destination: '/topic/logs',
    body: `
Ошибка подключения
Повторная попытка
Соединение восстановлено
`
});

Получатель получит полный текст вместе с переводами строк.


Использование шаблонных строк

Шаблонные строки позволяют удобно формировать сообщения.

const user = 'admin';
const action = 'login';

client.publish({
    destination: '/topic/activity',
    body: `${user} выполнил действие: ${action}`
});

Отправка JSON как текста

Наиболее распространённый сценарий — сериализация объекта в JSON.

const message = {
    id: 15,
    text: 'Привет',
    author: 'Alex'
};

client.publish({
    destination: '/topic/chat',
    body: JSON.stringify(message)
});

Получение:

client.subscribe('/topic/chat', message => {
    const data = JSON.parse(message.body);

    console.log(data.text);
});

Форматирование JSON

Для логирования или отладки иногда используют форматированный JSON.

client.publish({
    destination: '/topic/debug',
    body: JSON.stringify(data, null, 2)
});

Такой вариант увеличивает размер сообщения, но делает содержимое читаемым.


Отправка строковых команд

STOMP.js часто используется для передачи команд.

Пример:

client.publish({
    destination: '/app/commands',
    body: 'RESTART_SERVER'
});

Или:

client.publish({
    destination: '/app/commands',
    body: 'CLEAR_CACHE'
});

Передача пользовательских заголовков

STOMP позволяет прикреплять метаданные через headers.

Пример:

client.publish({
    destination: '/topic/chat',
    headers: {
        priority: 'high',
        sender: 'frontend'
    },
    body: 'Системное уведомление'
});

Получение заголовков:

client.subscribe('/topic/chat', message => {
    console.log(message.headers.priority);
    console.log(message.headers.sender);
});

Заголовок content-type

При отправке текстовых данных полезно явно указывать MIME-тип.

Пример:

client.publish({
    destination: '/topic/json',
    headers: {
        'content-type': 'application/json'
    },
    body: JSON.stringify({
        event: 'login'
    })
});

Для обычного текста:

headers: {
    'content-type': 'text/plain'
}

Для HTML:

headers: {
    'content-type': 'text/html'
}

Автоматический content-length

STOMP.js автоматически рассчитывает длину сообщения.

Пример:

client.publish({
    destination: '/topic/test',
    body: 'Hello'
});

Библиотека сама добавит:

content-length:5

Отключение content-length

Некоторые брокеры работают без заголовка длины.

Для этого используется:

client.publish({
    destination: '/topic/test',
    body: 'Hello',
    skipContentLengthHeader: true
});

Проверка подключения перед отправкой

Отправка без активного подключения вызывает ошибку.

Безопасный вариант:

if (client.connected) {
    client.publish({
        destination: '/topic/chat',
        body: 'Сообщение'
    });
}

Отправка после подключения

Частая ошибка — попытка публикации до завершения соединения.

Неправильно:

client.activate();

client.publish({
    destination: '/topic/chat',
    body: 'Текст'
});

Правильно:

client.onConn ect = () => {
    client.publish({
        destination: '/topic/chat',
        body: 'Текст'
    });
};

client.activate();

Массовая отправка сообщений

Пример пакетной публикации:

for (let i = 1; i <= 5; i++) {
    client.publish({
        destination: '/topic/counter',
        body: `Сообщение ${i}`
    });
}

Отправка с интервалом

setInterval(() => {
    client.publish({
        destination: '/topic/time',
        body: new Date().toISOString()
    });
}, 1000);

Отправка данных формы

const formData = {
    login: 'admin',
    password: '123456'
};

client.publish({
    destination: '/app/auth',
    body: JSON.stringify(formData)
});

Передача событий интерфейса

button.addEventListener('click', () => {
    client.publish({
        destination: '/topic/actions',
        body: 'button_click'
    });
});

Отправка сообщений из WebSocket-чата

sendButton.addEventListener('click', () => {
    const text = input.value;

    client.publish({
        destination: '/app/chat',
        body: JSON.stringify({
            text: text,
            date: Date.now()
        })
    });

    input.value = '';
});

Обработка пустых сообщений

STOMP допускает пустое тело сообщения.

client.publish({
    destination: '/topic/ping',
    body: ''
});

Иногда такие сообщения используются как сигналы или heartbeat-пакеты.


Отправка Unicode-символов

STOMP.js корректно работает с UTF-8.

Пример:

client.publish({
    destination: '/topic/chat',
    body: 'Привет 世界 ?'
});

Экранирование специальных символов

Тело сообщения не требует ручного экранирования.

client.publish({
    destination: '/topic/test',
    body: 'Строка с : двоеточием и\nпереносом'
});

STOMP.js самостоятельно обработает передачу данных.


Ограничения размера сообщений

Максимальный размер зависит от брокера.

Например:

  • RabbitMQ ограничивает размер настройками сервера
  • ActiveMQ может ограничивать размер фрейма
  • Spring Broker Relay зависит от WebSocket-конфигурации

Очень большие текстовые payload могут:

  • увеличивать задержки;
  • перегружать WebSocket;
  • вызывать разрыв соединения;
  • приводить к ошибкам памяти.

Отправка больших текстовых блоков

Пример:

const largeText = 'A'.repeat(500000);

client.publish({
    destination: '/topic/big',
    body: largeText
});

При работе с крупными сообщениями желательно:

  • использовать компрессию;
  • разбивать данные на части;
  • передавать ссылки вместо содержимого;
  • использовать бинарный формат.

Логирование отправляемых сообщений

Для диагностики удобно включать debug-режим.

client.debug = message => {
    console.log(message);
};

После этого STOMP.js начнёт выводить информацию о фреймах:

>>> SEND
destination:/topic/chat
content-length:5

Перехват ошибок отправки

Ошибки могут возникать при:

  • отсутствии соединения;
  • неверном destination;
  • отказе брокера;
  • превышении размера сообщения.

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

try {
    client.publish({
        destination: '/topic/chat',
        body: 'Hello'
    });
} catch (error) {
    console.error(error);
}

Отправка сообщений внутри транзакции

STOMP поддерживает транзакционные публикации.

Создание транзакции:

const tx = client.begin();

Отправка:

client.publish({
    destination: '/queue/tasks',
    body: 'Task 1',
    headers: {
        transaction: tx.id
    }
});

Подтверждение:

tx.commit();

Отмена:

tx.abort();

Асинхронная генерация текста перед отправкой

async function sendMessage() {
    const response = await fetch('/api/message');
    const text = await response.text();

    client.publish({
        destination: '/topic/server',
        body: text
    });
}

Повторная отправка при реконнекте

Во время потери соединения сообщения могут теряться.

Пример очереди повторной отправки:

const pendingMessages = [];

function send(text) {
    if (client.connected) {
        client.publish({
            destination: '/topic/chat',
            body: text
        });
    } else {
        pendingMessages.push(text);
    }
}

client.onConn ect = () => {
    while (pendingMessages.length > 0) {
        const text = pendingMessages.shift();

        client.publish({
            destination: '/topic/chat',
            body: text
        });
    }
};

Использование подтверждений доставки

Сам метод publish() не гарантирует доставку сообщения.

Гарантия зависит от:

  • режима ACK;
  • брокера;
  • транзакций;
  • персистентности сообщений;
  • серверной логики.

Для критически важных данных обычно используют:

  • очереди;
  • подтверждения обработки;
  • серверные ответы;
  • retry-механизмы.

Практический пример текстового чата

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

const client = new Client({
    brokerURL: 'ws://localhost:15674/ws'
});

client.onConn ect = () => {

    client.subscribe('/topic/chat', message => {
        console.log('Новое сообщение:', message.body);
    });

    document
        .getElementById('send')
        .addEventListener('click', () => {

            const input = document.getElementById('message');

            client.publish({
                destination: '/topic/chat',
                body: input.value
            });

            input.value = '';
        });
};

client.activate();

Частые ошибки при отправке текстовых данных

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

client.publish(...)

до onConnect.


Неверный destination

destination: 'chat'

Вместо:

destination: '/topic/chat'

Отсутствие сериализации JSON

Неправильно:

body: {
    text: 'Hello'
}

Правильно:

body: JSON.stringify({
    text: 'Hello'
})

Ошибка при разборе JSON

JSON.parse(message.body)

при получении обычного текста.


Отправка слишком больших сообщений

body: hugeData

может привести к закрытию соединения брокером.


Архитектурные рекомендации

Для текстовых сообщений обычно используют:

Тип данных Формат
Простые команды String
Структурированные данные JSON
Логи Plain Text
События JSON
Уведомления String / JSON

Практически все современные STOMP-приложения используют JSON как основной формат обмена данными благодаря:

  • совместимости;
  • удобству сериализации;
  • поддержке вложенных структур;
  • простоте обработки;
  • независимости от платформы.