You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Smack发送自定义格式消息触发‘not-well-formed’异常求助

解决Smack发送含控制字符消息触发的not-well-formed流错误

你的问题根源很明确:XMPP是基于XML的协议,而XML 1.0规范严格禁止在内容中使用ASCII控制字符(除了制表符\t、换行\n、回车\r),你用到的STX(0x2)、ETX(0x3)、US(0x1F)都属于被禁止的字符,当Smack尝试把包含这些字符的消息封装进XML流时,服务器会判定XML格式无效,直接触发not-well-formed错误并断开连接。

下面给你两种可行的解决方案,按需选择:

方案1:替换控制字符为XML友好的标记

把那些控制字符换成自定义的字符串标记,发送后在接收端再替换回原字符,完全避开XML的字符限制。

发送端修改代码

// 用XML允许的字符串替换控制字符
String STX = "<STX_MARKER>";
String ETX = "<ETX_MARKER>";
String US = "<US_MARKER>";

// 生成其他参数(保持你的原有逻辑)
String stringEncodedByteArray = Base64.getEncoder().encodeToString(bytes);
String fileID = java.util.UUID.randomUUID().toString();
String fileName = "file1";
String fileSize = "1000";
String senderID = "user1";

// 构建消息内容
String messageContent = STX + "1" + US + fileID + US + fileName + US + fileSize + US + senderID + US + stringEncodedByteArray + ETX;

// 发送消息(和你原来的发送逻辑一致)
Message message = new Message("recipient@yourdomain.com", Message.Type.chat);
message.setBody(messageContent);
connection.sendStanza(message);

接收端处理逻辑

// 收到消息后,把标记替换回原控制字符
String receivedBody = message.getBody();
String STX = Character.toString((char) 2);
String ETX = Character.toString((char) 3);
String US = Character.toString((char) 31);

String processedContent = receivedBody.replace("<STX_MARKER>", STX)
                                      .replace("<US_MARKER>", US)
                                      .replace("<ETX_MARKER>", ETX);

// 接下来按你的原有逻辑解析processedContent即可

方案2:使用XMPP标准扩展传输结构化数据

如果是传输文件相关数据,更推荐使用XMPP官方定义的扩展协议(比如XEP-0047 带内字节流、XEP-0234 Jingle文件传输),或者自定义消息扩展元素,这样完全符合XMPP规范,也更易维护。

比如自定义扩展元素的示例:

// 创建聊天消息
Message message = new Message("recipient@yourdomain.com", Message.Type.chat);

// 自定义文件信息扩展(指定一个唯一的命名空间)
DefaultElement fileInfoExt = new DefaultElement("file-info", "com.yourcompany.xmpp.filetransfer");
fileInfoExt.addAttribute("id", fileID);
fileInfoExt.addAttribute("name", fileName);
fileInfoExt.addAttribute("size", fileSize);
fileInfoExt.addAttribute("sender", senderID);

// 添加Base64编码的文件数据扩展
DefaultElement fileDataExt = new DefaultElement("file-data", "com.yourcompany.xmpp.filetransfer");
fileDataExt.setText(stringEncodedByteArray);

// 把扩展元素添加到消息中
message.addExtension(fileInfoExt);
message.addExtension(fileDataExt);

// 发送消息
connection.sendStanza(message);

接收端解析扩展

// 从收到的消息中获取扩展元素
Message receivedMsg = ...;
DefaultElement fileInfo = (DefaultElement) receivedMsg.getExtension("file-info", "com.yourcompany.xmpp.filetransfer");
DefaultElement fileData = (DefaultElement) receivedMsg.getExtension("file-data", "com.yourcompany.xmpp.filetransfer");

// 获取参数
String fileID = fileInfo.getAttributeValue("id");
String fileName = fileInfo.getAttributeValue("name");
// ... 其他参数
byte[] fileBytes = Base64.getDecoder().decode(fileData.getText());

这种方式不仅避免了控制字符的问题,还让数据结构更清晰,也符合XMPP的设计理念。

内容的提问来源于stack exchange,提问作者H3m4d

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:10:22