Методы отправки

В STOMP.js отправка сообщений реализуется через методы, которые инкапсулируют работу с STOMP-командами протокола и позволяют взаимодействовать с брокером сообщений (RabbitMQ, ActiveMQ, Apollo, SockJS + брокеры и др.). Основной механизм отправки базируется на команде SEND, которая формирует сообщение, направляемое в конкретный destination (очередь или топик).

Базовый метод отправки publish

В современных версиях STOMP.js (v5+ и актуальные реализации на основе @stomp/stompjs) основной метод отправки сообщений — publish.

Сигнатура метода:

client.publish({
  destination: string,
  body: string,
  headers?: object
});

Параметры

destination Строка, определяющая маршрут сообщения на брокере. Это может быть:

  • очередь: /queue/task
  • топик: /topic/chat
  • кастомный endpoint, зависящий от конфигурации брокера

body Строка с полезной нагрузкой сообщения. STOMP не накладывает ограничений на формат, однако чаще всего используется:

  • JSON (JSON.stringify)
  • строки
  • сериализованные структуры

headers Дополнительные STOMP-заголовки, влияющие на обработку сообщения:

  • content-type
  • priority
  • persistent
  • пользовательские заголовки

Пример:

client.publish({
  destination: "/queue/orders",
  body: JSON.stringify({ id: 123, status: "created" }),
  headers: {
    "content-type": "application/json"
  }
});

Метод send (устаревшие реализации)

В более старых версиях STOMP.js использовался метод send, который сохраняется для совместимости.

Сигнатура:

client.send(destination, headers, body);

Особенности

  • менее гибкая структура аргументов
  • сложнее расширять функциональность
  • отсутствует единый объект конфигурации

Пример:

client.send(
  "/topic/messages",
  { "content-type": "text/plain" },
  "Hello world"
);

Использование send в новых проектах считается нежелательным, поскольку он не соответствует современному API подходу с объектной конфигурацией.


Формирование тела сообщения

STOMP.js не ограничивает формат тела, однако практическое применение требует стандартизации.

Строковые сообщения

Самый простой вариант:

client.publish({
  destination: "/queue/logs",
  body: "system started"
});

Используется для:

  • логирования
  • простых событий
  • управляющих сигналов

JSON-сообщения

Наиболее распространённый формат:

client.publish({
  destination: "/topic/user.events",
  body: JSON.stringify({
    userId: 42,
    action: "login",
    timestamp: Date.now()
  }),
  headers: {
    "content-type": "application/json"
  }
});

Особенности:

  • требует явной сериализации
  • на стороне сервера выполняется обратный parse
  • рекомендуется фиксировать схему сообщений

Бинарные данные (через ArrayBuffer / Uint8Array)

Некоторые реализации STOMP позволяют передавать бинарные данные, но поддержка зависит от брокера и транспорта.

const encoder = new TextEncoder();
const data = encoder.encode("binary payload");

client.publish({
  destination: "/queue/binary",
  binaryBody: data
});

Важно учитывать:

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

Заголовки сообщений

STOMP-заголовки позволяют управлять поведением доставки и обработки сообщений.

Стандартные заголовки

content-type Определяет формат тела:

headers: {
  "content-type": "application/json"
}

persistent Указывает брокеру сохранять сообщение:

headers: {
  persistent: "true"
}

priority Приоритет обработки сообщения:

headers: {
  priority: "9"
}

Пользовательские заголовки

Можно добавлять любые метаданные:

client.publish({
  destination: "/queue/audit",
  body: "update",
  headers: {
    "x-user-id": "42",
    "x-request-id": "abc-123",
    "x-source": "frontend"
  }
});

Используется для:

  • трассировки запросов
  • авторизации
  • бизнес-логики маршрутизации

Управление очередями и топиками через отправку

В STOMP различают два основных типа маршрутов:

Очереди (queues)

Сообщение получает один потребитель:

client.publish({
  destination: "/queue/tasks",
  body: JSON.stringify({ task: "resize-image" })
});

Характеристики:

  • load balancing между consumers
  • гарантированная доставка одному получателю

Топики (topics)

Сообщение получают все подписчики:

client.publish({
  destination: "/topic/notifications",
  body: "new update available"
});

Характеристики:

  • pub/sub модель
  • широковещательная доставка
  • отсутствие хранения без durable subscription

Отправка сообщений с подтверждением логики приложения

STOMP не предоставляет встроенных callback-ответов на publish, однако можно реализовать корреляцию сообщений.

Correlation ID

const correlationId = crypto.randomUUID();

client.publish({
  destination: "/queue/requests",
  body: JSON.stringify({ action: "process" }),
  headers: {
    "correlation-id": correlationId,
    "reply-to": "/queue/responses"
  }
});

Используется вместе с подпиской на ответный канал.


Таймауты и контроль отправки

STOMP.js не управляет таймаутами отправки напрямую, но их можно реализовать на уровне приложения.

Пример логики:

function publishWithTimeout(client, message, timeout = 5000) {
  const id = crypto.randomUUID();

  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error("Timeout sending message"));
    }, timeout);

    client.publish({
      destination: "/queue/tasks",
      body: JSON.stringify(message),
      headers: {
        "message-id": id
      }
    });

    resolve({ id });
    clearTimeout(timer);
  });
}

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

STOMP.js не предоставляет batch API, но массовая отправка реализуется через цикл.

const messages = [
  { id: 1 },
  { id: 2 },
  { id: 3 }
];

messages.forEach(msg => {
  client.publish({
    destination: "/queue/batch",
    body: JSON.stringify(msg)
  });
});

Оптимизация:

  • объединение сообщений в одно
  • использование серверной декомпозиции
  • контроль нагрузки брокера

Поведение при отсутствии соединения

Если соединение с брокером отсутствует:

  • сообщения могут быть отброшены
  • или поставлены в очередь (зависит от реализации клиента)

Типичная защита:

if (client.connected) {
  client.publish({
    destination: "/queue/secure",
    body: "data"
  });
}

Более устойчивый вариант — буферизация:

const queue = [];

function safePublish(msg) {
  if (!client.connected) {
    queue.push(msg);
    return;
  }

  client.publish(msg);
}

Работа с транзакциями отправки

Некоторые брокеры поддерживают STOMP-транзакции.

const tx = client.begin();

client.publish({
  destination: "/queue/tx",
  body: "part 1",
  transaction: tx.id
});

client.publish({
  destination: "/queue/tx",
  body: "part 2",
  transaction: tx.id
});

tx.commit();

Возможные операции:

  • begin()
  • commit()
  • abort()

Транзакции обеспечивают атомарность отправки сообщений в рамках брокера.


Особенности сериализации данных

Перед отправкой важно учитывать:

  • STOMP передаёт только строки или байты
  • объекты требуют сериализации
  • числовые значения приводятся к строкам автоматически

Рекомендованный подход:

body: JSON.stringify(payload)

Ошибки частого типа:

  • отправка объекта без сериализации
  • несоответствие content-type
  • потеря структуры данных при десериализации

Ограничения и практические нюансы

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

Архитектурно STOMP.js следует рассматривать как тонкий транспортный слой, а не как систему гарантированной доставки.