Заголовки (headers) в протоколе STOMP используются для передачи
дополнительной служебной информации вместе с кадрами
(FRAME). Они играют ключевую роль в аутентификации,
маршрутизации, управлении сообщениями, настройке подписок и
взаимодействии с брокером сообщений.
В библиотеке STOMP.js заголовки передаются практически во всех операциях:
CONNECT)SEND)SUBSCRIBE)ACK)BEGIN, COMMIT,
ABORT)DISCONNECT)Каждый заголовок представляет собой пару
ключ: значение.
Пример STOMP-кадра:
SEND
destination:/queue/chat
content-type:application/json
priority:9
{"message":"Hello"}
Внутри STOMP.js заголовки обычно задаются в виде объекта JavaScript.
Базовая структура выглядит следующим образом:
{
headerName: 'value',
anotherHeader: 'anotherValue'
}
Пример:
client.publish({
destination: '/queue/test',
headers: {
priority: '9',
persistent: 'true'
},
body: 'Test message'
});
STOMP.js автоматически преобразует объект headers в
STOMP-заголовки кадра.
Во время подключения заголовки используются для:
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: {
login: 'admin',
passcode: 'admin'
}
});
В результате формируется кадр:
CONNECT
login:admin
passcode:admin
Некоторые брокеры требуют указания виртуального хоста.
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: {
host: '/'
}
});
Особенно часто это используется в:
Современные приложения часто используют токены авторизации.
const client = new Client({
brokerURL: 'ws://localhost:8080/ws',
connectHeaders: {
Authorization: 'Bearer eyJhbGciOiJIUzI1Ni...'
}
});
На сервере заголовок может быть обработан middleware или interceptor-механизмом.
STOMP не ограничивает набор пользовательских заголовков.
connectHeaders: {
clientId: 'frontend-app',
appVersion: '2.5.1',
region: 'kz'
}
Сервер может использовать их:
Наиболее распространённое место использования заголовков — операция
SEND.
client.publish({
destination: '/queue/chat',
headers: {
type: 'notification'
},
body: 'New message'
});
Определяет тип содержимого сообщения.
client.publish({
destination: '/queue/events',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
id: 15,
status: 'created'
})
});
headers: {
'content-type': 'text/plain'
}
headers: {
'content-type': 'application/xml'
}
Некоторые брокеры автоматически вычисляют длину содержимого, однако иногда требуется установить её вручную.
const body = JSON.stringify(data);
client.publish({
destination: '/queue/test',
headers: {
'content-length': body.length.toString()
},
body
});
Обычно STOMP.js сам управляет этим заголовком.
Ручная установка используется редко.
Определяет, должно ли сообщение сохраняться брокером.
client.publish({
destination: '/queue/orders',
headers: {
persistent: 'true'
},
body: 'Order created'
});
Если брокер поддерживает persistent-сообщения:
Позволяет задавать приоритет сообщения.
client.publish({
destination: '/queue/tasks',
headers: {
priority: '9'
},
body: 'Critical task'
});
Чаще всего диапазон:
0–9
Где:
0 — минимальный приоритет9 — максимальныйПоддержка зависит от брокера.
Устанавливает время жизни сообщения.
client.publish({
destination: '/queue/cache',
headers: {
expires: (Date.now() + 60000).toString()
},
body: 'Temporary data'
});
После истечения времени брокер может:
Используется для подтверждения выполнения операции брокером.
client.publish({
destination: '/queue/test',
headers: {
receipt: 'msg-001'
},
body: 'Test'
});
client.onRece ipt = (frame) => {
console.log('Receipt received:', frame.headers['receipt-id']);
};
Брокер вернёт:
RECEIPT
receipt-id:msg-001
Подписки (SUBSCRIBE) активно используют заголовки.
Каждая подписка должна иметь уникальный идентификатор.
client.subscribe('/topic/news', callback, {
id: 'news-subscription'
});
Без уникального id некоторые брокеры отклоняют
подписку.
Управляет режимом подтверждения сообщений.
ack: 'auto'
Сообщение считается подтверждённым автоматически.
ack: 'client'
Подтверждение выполняется вручную:
message.ack();
ack: 'client-individual'
Каждое сообщение подтверждается отдельно.
client.subscribe('/topic/orders', callback, {
region: 'eu',
service: 'billing'
});
Сервер может фильтровать подписчиков по этим параметрам.
При ручном подтверждении сообщений STOMP.js формирует специальные заголовки автоматически.
Пример:
message.ack({
transaction: 'tx-1'
});
STOMP.js добавит:
ACK
id:message-id
subscription:sub-0
transaction:tx-1
Некоторые брокеры поддерживают отрицательное подтверждение.
message.nack();
Можно передавать дополнительные заголовки:
message.nack({
requeue: 'true'
});
STOMP поддерживает транзакционный режим работы.
client.begin('tx-1');
Или:
client.begin('tx-1', {
priority: '5'
});
client.commit('tx-1');
client.abort('tx-1');
Часть заголовков библиотека генерирует самостоятельно.
Примеры:
accept-version
heart-beat
content-length
destination
subscription
message-id
Обычно переопределять их не требуется.
Все входящие заголовки доступны через объект
message.headers.
client.subscribe('/queue/chat', (message) => {
console.log(message.headers);
});
const type = message.headers.type;
Или:
const contentType = message.headers['content-type'];
MESSAGE
destination:/queue/chat
content-type:application/json
message-id:007
priority:8
{"text":"Hello"}
Извлечение:
client.subscribe('/queue/chat', (message) => {
console.log(message.headers['message-id']);
console.log(message.headers.priority);
});
STOMP-заголовки чувствительны к регистру.
Корректно:
'content-type'
Некорректно:
'Content-Type'
Некоторые брокеры могут игнорировать неправильный регистр.
STOMP 1.1+ поддерживает экранирование:
| Символ | Экранирование |
|---|---|
\n |
перевод строки |
\c |
двоеточие |
\\ |
обратный слэш |
Пример:
custom-header:line1\nline2
STOMP.js обычно выполняет экранирование автоматически.
При совпадении имён побеждает последнее значение.
headers: {
priority: '1',
priority: '9'
}
Результат:
priority:9
Часто заголовки создаются во время выполнения.
const headers = {
Authorization: `Bearer ${token}`,
requestId: crypto.randomUUID(),
timestamp: Date.now().toString()
};
client.publish({
destination: '/queue/api',
headers,
body: payload
});
const commonHeaders = {
app: 'frontend',
version: '1.0'
};
client.publish({
destination: '/queue/test',
headers: {
...commonHeaders,
priority: '5'
},
body: 'Test'
});
В крупных приложениях удобно выносить общие заголовки в отдельный модуль.
export function createHeaders(token) {
return {
Authorization: `Bearer ${token}`,
client: 'web-app'
};
}
Использование:
client.publish({
destination: '/queue/orders',
headers: createHeaders(token),
body: JSON.stringify(order)
});
На серверной стороне заголовки часто используются для:
Пример correlation-id:
headers: {
'correlation-id': crypto.randomUUID()
}
'Content-Type'
Вместо:
'content-type'
Некоторые брокеры ожидают строковые значения.
Плохо:
priority: 5
Лучше:
priority: '5'
client.subscribe('/topic/test', callback);
Некоторые брокеры могут отклонить такую подписку.
Опасно переопределять:
destinationcontent-lengthsubscriptionmessage-idЭто может привести к ошибкам протокола.
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: {
login: 'admin',
passcode: 'admin',
Authorization: `Bearer ${token}`,
clientId: 'frontend-app'
}
});
client.onConn ect = () => {
client.subscribe('/queue/orders', (message) => {
console.log(message.body);
message.ack({
transaction: 'tx-order'
});
}, {
id: 'orders-sub',
ack: 'client'
});
client.publish({
destination: '/queue/orders',
headers: {
'content-type': 'application/json',
persistent: 'true',
priority: '8',
receipt: 'order-001',
'correlation-id': crypto.randomUUID()
},
body: JSON.stringify({
orderId: 15,
amount: 250
})
});
};
client.activate();