Миграция между версиями STOMP.js чаще всего связана со следующими изменениями:
Stomp;Особенно заметны изменения при переходе:
stompjs → @stomp/stompjs;stompjsРанние проекты часто использовали библиотеку:
npm install stompjs
Импорт обычно выглядел следующим образом:
import Stomp from 'stompjs';
Или:
<script src="stomp.min.js"></script>
Создание клиента:
const socket = new WebSocket('ws://localhost:15674/ws');
const client = Stomp.over(socket);
client.connect({}, () => {
console.log('Connected');
});
Главные особенности старой архитектуры:
@stomp/stompjsНовая библиотека устанавливается так:
npm install @stomp/stompjs
Импорт:
import { Client } from '@stomp/stompjs';
Создание клиента:
const client = new Client({
brokerURL: 'ws://localhost:15674/ws'
});
Подключение:
client.activate();
Главное отличие — объект Client теперь управляет всем
жизненным циклом соединения.
Stomp.over() на Clientconst socket = new WebSocket(url);
const client = Stomp.over(socket);
client.connect(headers, onConnect);
const client = new Client({
brokerURL: url,
connectHeaders: headers,
onConnect: () => {
console.log('Connected');
}
});
client.activate();
Изменения:
| Старый API | Новый API |
|---|---|
Stomp.over() |
new Client() |
connect() |
activate() |
disconnect() |
deactivate() |
debug = fn |
debug: fn |
reconnect_delay |
reconnectDelay |
client.connect(
{
login: 'admin',
passcode: 'admin'
},
() => {
console.log('Connected');
},
(error) => {
console.error(error);
}
);
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: {
login: 'admin',
passcode: 'admin'
},
onConnect: () => {
console.log('Connected');
},
onStompError: (frame) => {
console.error(frame);
}
});
Новая модель убирает длинные callback-цепочки и делает конфигурацию декларативной.
Ранее reconnect выглядел так:
client.reconnect_delay = 5000;
Это поле изменялось напрямую после создания клиента.
Теперь reconnect задаётся через конфигурацию:
const client = new Client({
brokerURL: url,
reconnectDelay: 5000
});
Либо:
client.reconnectDelay = 5000;
Современный reconnect работает стабильнее:
client.heartbeat.outgoing = 20000;
client.heartbeat.incoming = 0;
API сохранилось, но применяется через Client:
const client = new Client({
heartbeatIncoming: 0,
heartbeatOutgoing: 20000
});
Допускается и динамическое изменение:
client.heartbeatIncoming = 0;
client.heartbeatOutgoing = 20000;
Старые версии использовали callbacks прямо внутри
connect():
client.connect(headers, onConnect, onError);
Современные версии используют lifecycle handlers:
const client = new Client({
onConnect: () => {},
onDisconnect: () => {},
onWebSocketClose: () => {},
onWebSocketError: () => {},
onStompError: () => {}
});
Преимущества:
client.subscribe('/queue/test', (message) => {
console.log(message.body);
});
Синтаксис почти не изменился:
client.subscribe('/queue/test', (message) => {
console.log(message.body);
});
Но изменилось поведение reconnect.
В старых версиях после reconnect подписки могли теряться.
В новых версиях:
client.send(
'/queue/test',
{
priority: 9
},
JSON.stringify(data)
);
client.publish({
destination: '/queue/test',
headers: {
priority: 9
},
body: JSON.stringify(data)
});
Причины изменения:
send() на
publish()Старый API:
client.send(destination, headers, body);
Проблемы:
null;Новый API:
client.publish({
destination,
headers,
body
});
Преимущества:
client.disconnect(() => {
console.log('Disconnected');
});
await client.deactivate();
Либо:
client.deactivate().then(() => {
console.log('Disconnected');
});
Теперь отключение основано на Promise API.
Старые версии активно использовали callbacks:
client.disconnect(callback);
Новые версии используют Promise:
await client.deactivate();
Это упрощает:
client.debug = (message) => {
console.log(message);
};
const client = new Client({
debug: (message) => {
console.log(message);
}
});
Либо:
client.debug = console.log;
Современные версии позволяют централизованно отключать debug:
const client = new Client({
debug: () => {}
});
Либо:
const client = new Client({
debug: process.env.NODE_ENV === 'development'
? console.log
: () => {}
});
Ранее SockJS часто использовался автоматически:
const socket = new SockJS('/ws');
const client = Stomp.over(socket);
В новых версиях SockJS интегрируется через
webSocketFactory.
import SockJS from 'sockjs-client';
import { Client } from '@stomp/stompjs';
const client = new Client({
webSocketFactory: () => {
return new SockJS('/ws');
}
});
Причины изменений:
Старые версии:
client.connect();
Соединение создавалось сразу.
Новые версии:
client.activate();
Клиент переходит в активное состояние и сам управляет подключением.
Это важно для:
client.connect({}, onConnect, (error) => {
console.error(error);
});
const client = new Client({
onStompError: (frame) => {
console.error(frame.headers['message']);
console.error(frame.body);
}
});
Дополнительно появились:
onWebSocketError
onWebSocketClose
onDisconnect
Теперь можно отдельно обрабатывать:
message.ack();
И:
message.nack();
API осталось похожим:
message.ack();
message.nack();
Но изменилась внутренняя реализация:
const tx = client.begin();
client.send('/queue/test', {}, 'message');
tx.commit();
const tx = client.begin();
client.publish({
destination: '/queue/test',
body: 'message',
transaction: tx.id
});
tx.commit();
Старые версии практически не имели нормальной TypeScript-поддержки.
Новые версии:
import { Client, IMessage } from '@stomp/stompjs';
const client: Client = new Client();
client.onConn ect = () => {};
client.subscribe('/queue/test', (message: IMessage) => {
console.log(message.body);
});
Преимущества:
Старые проекты:
const Stomp = require('stompjs');
Новые проекты:
import { Client } from '@stomp/stompjs';
Некоторые старые webpack-конфигурации ожидают:
module.exports
Но современный пакет ориентирован на:
export
Из-за этого возникают ошибки:
Client is not a constructor
или:
Cannot read property 'over' of undefined
const socket = new SockJS('/ws');
const client = Stomp.over(socket);
client.connect({}, () => {
client.send('/topic/chat', {}, 'Hello');
});
import SockJS from 'sockjs-client';
import { Client } from '@stomp/stompjs';
const client = new Client({
webSocketFactory: () => new SockJS('/ws'),
onConnect: () => {
client.publish({
destination: '/topic/chat',
body: 'Hello'
});
}
});
client.activate();
connect()После миграции многие продолжают вызывать:
client.connect();
В новых версиях правильный вариант:
client.activate();
send()Старый API:
client.send(...);
Новый API:
client.publish(...);
disconnect()Старый API:
client.disconnect();
Новый API:
await client.deactivate();
Stomp.over()В новых версиях:
Stomp.over()
чаще всего отсутствует.
Необходимо использовать:
new Client()
Современный STOMP.js:
В крупных приложениях переход обычно выполняется поэтапно.
Часто используется адаптер:
class LegacyStompAdapter {
constructor(url) {
this.client = new Client({
brokerURL: url
});
}
connect(headers, callback) {
this.client.onConn ect = callback;
this.client.activate();
}
send(destination, headers, body) {
this.client.publish({
destination,
headers,
body
});
}
}
Такой подход позволяет:
При переходе необходимо проверять:
Особенно важно тестировать:
Современный STOMP.js лучше поддерживает:
Старые версии плохо работали с binary payload.
Новые версии поддерживают:
client.publish({
destination: '/queue/file',
binaryBody: uint8Array
});
Получение:
client.subscribe('/queue/file', (message) => {
const data = message.binaryBody;
});
client.send('/queue/test', {
receipt: '123'
}, 'hello');
client.watchForReceipt('123', () => {
console.log('Received');
});
client.publish({
destination: '/queue/test',
headers: {
receipt: '123'
},
body: 'hello'
});
Наиболее безопасная стратегия:
Stomp.over;connect;send;disconnect;import SockJS from 'sockjs-client';
import { Client } from '@stomp/stompjs';
const client = new Client({
webSocketFactory: () => {
return new SockJS('/ws');
},
reconnectDelay: 5000,
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000,
connectHeaders: {
login: 'admin',
passcode: 'admin'
},
debug: console.log,
onConnect: () => {
console.log('Connected');
client.subscribe('/topic/chat', (message) => {
console.log(message.body);
});
client.publish({
destination: '/topic/chat',
body: 'Hello'
});
},
onStompError: (frame) => {
console.error(frame);
},
onWebSocketClose: () => {
console.log('Socket closed');
}
});
client.activate();