Python通过STOMP向ActiveMQ Artemis发消息时JMSMessageID缺失问题
我用Python通过STOMP协议向ActiveMQ Artemis队列发送消息,Spring JMS应用接收时抛出异常:
NoJMSMessageIdException: MISSING_JMS_MESSAGE_ID.
我尝试设置JMSMessageID、msgID、MESSAGE_ID等多种消息头或属性,甚至按文档要求添加ID:前缀,但都没解决问题。我的应用通过javax.jms.Message.getJMSMessageID()方法验证消息,请问这个方法期望的JMSMessageID格式是什么?如何在Python STOMP客户端正确设置并发送?
Python STOMP客户端文档只提供发送示例,未说明如何设置JMSMessageID,发送方法定义如下:
Protocol12.send(destination, body, content_type=None, headers=None, **keyword_headers)
向消息系统的目标发送消息(遵循STOMP 1.2规范)
参数:
- destination (str) – 消息目标(如队列'/queue/test'或主题)
- body: 消息内容
- content_type (str): 消息MIME类型
- headers (dict): 消息帧中的额外头信息
- keyword_headers: 代理要求的其他额外头信息
我的代码如下:
import stomp import json jsonRequest = { "data": { "key": "value" } } class MyListener(stomp.ConnectionListener): def on_error(self, frame): print('received an error "%s"' % frame.body) def on_message(self, frame): print('received a message "%s"' % frame.body) conn = stomp.Connection([('host', 63001)]) conn.set_listener('', MyListener()) conn.connect('user', 'password', wait=True) conn.subscribe(destination='queue', id=1, ack='auto') conn.send(destination='queue', body=json.dumps(jsonRequest), MESSAGE_ID='e5bf8c3d-0dc4-11ed-a28a-544d36153f8c', JMSMessageID='ID:e5bf8c3d-0dc4-11ed-a28a-544d36153f5c', headers={'MESSAGE_ID': 'ID:e5bf8c3d-0dc4-11ed-a28a-544d36153f5c', 'JMSCorrelationID': '123278256677', 'JMSReplyTo': 'queue'}, MSGUID="3e4fb627-85df-4b37-b37b-1070c7893c99", TotalNumberMsg=1, CurrentNumberMsg=1, UIPSYSTEMDATA=72) test = MyListener()
后端服务错误日志:
2022-07-27 20:10:53 [,] [DefaultMessageListenerContainer-2] ERROR service.jms.listener.base.AbstractArtemisMessageListener - Exception while processing message MISSING_JMS_MESSAGE_ID service.exception.NoJMSMessageIdException: MISSING_JMS_MESSAGE_ID
用JMS ToolBox发送的消息有正确ID:
2022-07-27 18:58:03 [,] [DefaultMessageListenerContainer-2] INFO service.jms.listener.base.AbstractArtemisMessageListener - Message from srv: ActiveMQMessage[ID:e5bf8c3d-0dc4-11ed-a28a-544d36153f0c]:PERSISTENT/ClientLargeMessageImpl[messageID=318412845, durable=true, address=queue,userID=e5bf8c3d-0dc4-11ed-a28a-544d36153f0c,properties=TypedProperties[__AMQ_CID=JMSToolBox-1657948224556,TotalNumberMsg=1,JMSReplyTo=queue://,_AMQ_ROUTING_TYPE=1,MSGUID=3e4fb627-85df-4b37-b37b-1070c7893c82,SERVICENAME=service,JMSCorrelationID=5515D5431364567,_AMQ_VALIDATED_USER=ACTIVEMQ.CLUSTER.ADMIN.USER,CurrentNumberMsg=1,UIPSYSTEMDATA=063224508,_AMQ_LARGE_SIZE=308737]] with correlationId: 5515D5431364567
而STOMP发送的消息中JMSMessageID为NULL:
2022-07-27 19:12:52 [,] [DefaultMessageListenerContainer-2] INFO service.jms.listener.base.AbstractArtemisMessageListener - Message from srv: ActiveMQMessage[null]:NON-PERSISTENT/ClientLargeMessageImpl[messageID=318581407, durable=false, address=queue,userID=null,properties=TypedProperties[content-length=110919,destination=queue,JMSReplyTo=queue,TotalNumberMsg=1,_AMQ_ROUTING_TYPE=1,MSGUID=3e4fb627-85df-4b37-b37b-1070c7893c99,SERVICENAME=service,JMSCorrelationID=123278256677,_AMQ_VALIDATED_USER=ACTIVEMQ.CLUSTER.ADMIN.USER,CurrentNumberMsg=1,UIPSYSTEMDATA=72,_AMQ_LARGE_SIZE=110919,messageID=125774553292,JMSType=NULL-value]] with correlationId: 123278256677
1. JMSMessageID的标准格式
javax.jms.Message.getJMSMessageID()要求的格式是ID:<唯一标识符>,其中唯一标识符通常是UUID或类似的全局唯一字符串(比如日志里的ID:e5bf8c3d-0dc4-11ed-a28a-544d36153f0c)。这个格式是JMS规范定义的,代理会将符合该格式的头映射到JMSMessageID字段。
2. Python STOMP客户端的正确设置方法
ActiveMQ Artemis对于STOMP协议的消息,需要通过特定的STOMP头来传递JMSMessageID,而不是直接用JMSMessageID作为头名。正确的头是AMQ_JMS_MESSAGE_ID,需要将值设置为ID:<UUID>格式。
另外需要注意:
- STOMP头名是大小写敏感的,必须严格使用
AMQ_JMS_MESSAGE_ID - 消息要设置为持久化(添加
persistent='true'头),否则代理可能不会正确处理JMS属性映射
3. 修正后的代码示例
import stomp import json import uuid jsonRequest = { "data": { "key": "value" } } class MyListener(stomp.ConnectionListener): def on_error(self, frame): print('received an error "%s"' % frame.body) def on_message(self, frame): print('received a message "%s"' % frame.body) # 生成符合格式的JMSMessageID message_id = f"ID:{uuid.uuid1()}" conn = stomp.Connection([('host', 63001)]) conn.set_listener('', MyListener()) conn.connect('user', 'password', wait=True) conn.subscribe(destination='queue', id=1, ack='auto') # 正确设置头信息 conn.send( destination='queue', body=json.dumps(jsonRequest), headers={ 'AMQ_JMS_MESSAGE_ID': message_id, 'JMSCorrelationID': '123278256677', 'JMSReplyTo': 'queue', 'persistent': 'true' # 持久化消息,确保JMS属性被正确处理 }, MSGUID="3e4fb627-85df-4b37-b37b-1070c7893c99", TotalNumberMsg=1, CurrentNumberMsg=1, UIPSYSTEMDATA=72 ) test = MyListener()
4. 验证逻辑
发送后查看后端日志,若消息日志显示ActiveMQMessage[ID:xxx]而非null,则说明JMSMessageID设置成功,NoJMSMessageIdException会被解决。
内容的提问来源于stack exchange,提问作者EvgeniY S

