ActiveMQ-Artemis中Java消息无法被STOMP JS客户端接收
问题根因
故障出在Java端ActiveMQ Artemis Core API的消息构造逻辑不符合STOMP协议的解析规则,具体有两点问题:
- 调用
session.createMessage(false)默认创建的是字节类型(BYTES_TYPE)消息,没有显式标记消息类型,也未设置content-type消息头。STOMP协议栈和stompjs客户端无法识别无类型标识的原始字节消息,收到帧后不会触发业务消息回调,也不会返回ACK确认,直接表现为JS端收不到消息、队列中100条Java发送的消息长期停留在投递状态。 - 直接调用
getBodyBuffer().writeBytes()写入原始字节的操作不符合Core API规范:Core消息的缓冲区预留了协议头存储位,裸写字节会导致消息体偏移错误。
控制台发送、JS端发送的消息可以被所有消费者正常接收,是因为这两个客户端发送消息时会自动将消息标记为文本类型,同时携带text/plain的content-type属性,协议层可以正常解析路由。
修复方案
无需调整Broker配置和前端JS代码,仅修改Java端的消息发送、消费逻辑即可:
- 创建消息时显式指定为文本类型,添加content-type属性兼容STOMP协议解析
- 使用Core API内置的字符串读写方法操作消息体,避免手动处理字节数组
消息发送逻辑修改
原发送代码:
for (int i = 0; i < 100; i++) { String payload = "Message from java " + i; ClientMessage message = session.createMessage(false); message.getBodyBuffer().writeBytes(payload.getBytes()); producer.send("broadcastMessage", message); Thread.sleep(1000); }
替换为:
// 类顶部添加常量导入 import static org.apache.activemq.artemis.api.core.Message.HDR_CONTENT_TYPE; // 其他业务逻辑保持不变 for (int i = 0; i < 100; i++) { String payload = "Message from java " + i; // 显式创建文本类型非持久消息 ClientMessage message = session.createMessage(ClientMessage.TEXT_TYPE, false); // 直接写入字符串内容,无需手动转字节数组 message.getBodyBuffer().writeString(payload); // 设置内容类型头,供STOMP协议识别 message.putStringProperty(HDR_CONTENT_TYPE, "text/plain"); producer.send("broadcastMessage", message); Thread.sleep(1000); }
消息消费逻辑修改
原消费处理代码:
consumer.setMessageHandler(message -> { byte[] bytes = new byte[message.getBodyBuffer().readableBytes()]; message.getDataBuffer().readBytes(bytes); System.out.println("Received " + new String(bytes)); });
替换为:
consumer.setMessageHandler(message -> { // 文本消息直接调用内置方法读取,避免字节解析错误 System.out.println("Received " + message.getBodyBuffer().readString()); });
验证
修改后重启Java进程,JS端可正常接收Java进程发送的所有消息,Artemis控制台中STOMP专属队列的投递消息会全部完成确认,不会再出现消息卡投递的问题。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

