求助:ReactJS中使用Stanza.io发送带自定义属性消息的示例
在React中使用Stanza.io发送带自定义属性的消息
我之前也碰到过在Stanza.io里发送带自定义属性消息的需求,折腾了一阵才搞清楚正确的实现方式——核心是利用Stanza的消息扩展机制,要么给<message>元素本身加自定义属性,要么添加符合XMPP规范的自定义扩展节点。下面是一个完整的React组件示例,涵盖了从连接XMPP服务器到发送、解析自定义消息的全部流程:
import React, { useState, useEffect } from 'react'; import { Client, xml } from 'stanza.io'; const XMPPChat = () => { const [client, setClient] = useState(null); const [isConnected, setIsConnected] = useState(false); const [messageText, setMessageText] = useState(''); const [receivedMessages, setReceivedMessages] = useState([]); useEffect(() => { // 初始化Stanza客户端 const xmppClient = new Client({ jid: 'your-username@example.com', // 替换为你的XMPP账号JID password: 'your-password', // 替换为你的账号密码 transport: 'websocket', wsURL: 'wss://example.com:5281/xmpp-websocket' // 替换为你的XMPP服务器WebSocket地址 }); // 连接成功回调 xmppClient.on('session:started', () => { setIsConnected(true); console.log('XMPP连接成功'); // 发送在线状态 xmppClient.sendPresence(); }); // 接收消息回调 xmppClient.on('message', (msg) => { if (msg.type !== 'error') { // 1. 解析<message>元素本身的自定义属性 const customUserId = msg.attrs['custom-user-id']; const customType = msg.attrs['custom-message-type']; if (customUserId && customType) { console.log('消息自带的自定义属性:', { customUserId, customType }); } // 2. 解析自定义扩展节点 const customNode = msg.getChild('custom', 'http://your-custom-namespace.com'); if (customNode) { const userId = customNode.attrs.userId; const messageType = customNode.attrs.messageType; const metadataPriority = customNode.getChild('metadata')?.attrs.priority; console.log('自定义扩展内容:', { userId, messageType, metadataPriority }); } // 将普通消息内容加入列表 setReceivedMessages(prev => [...prev, msg.body]); } }); // 连接错误处理 xmppClient.on('error', (err) => { console.error('XMPP连接出错:', err); setIsConnected(false); }); // 启动连接 xmppClient.connect(); setClient(xmppClient); // 组件卸载时断开连接 return () => { if (xmppClient) { xmppClient.disconnect(); } }; }, []); // 发送带自定义属性的消息(直接给<message>元素加属性) const sendCustomMessageWithAttrs = () => { if (!client || !messageText.trim() || !isConnected) return; client.sendMessage({ to: 'recipient@example.com', // 替换为接收者的JID body: messageText, attrs: { 'custom-user-id': 'user_123', 'custom-message-type': 'system_notification' } }); setMessageText(''); }; // 发送带自定义扩展节点的消息(更符合XMPP规范,适合复杂数据) const sendCustomMessageWithExtension = () => { if (!client || !messageText.trim() || !isConnected) return; // 创建自定义扩展节点,必须指定唯一命名空间 const customExtension = xml( 'custom', 'http://your-custom-namespace.com', { userId: 'user_123', messageType: 'system_notification' }, // 可以嵌套子节点存储更多元数据 xml('metadata', null, { priority: 'high', timestamp: Date.now().toString() }) ); client.sendMessage({ to: 'recipient@example.com', // 替换为接收者的JID body: messageText, extensions: [customExtension] }); setMessageText(''); }; return ( <div style={{ maxWidth: 600, margin: '20px auto', padding: '0 20px' }}> <h2>Stanza.io 自定义消息测试</h2> <div style={{ marginBottom: 20 }}> <p>连接状态: {isConnected ? '✅ 已连接' : '❌ 未连接'}</p> </div> <div style={{ marginBottom: 20 }}> <h3>接收的消息:</h3> <div style={{ border: '1px solid #eee', borderRadius: 4, padding: 12, height: 220, overflowY: 'auto' }}> {receivedMessages.length === 0 ? ( <p style={{ color: '#999' }}>暂无消息</p> ) : ( receivedMessages.map((msg, idx) => ( <p key={idx} style={{ margin: '8px 0' }}>{msg}</p> )) )} </div> </div> <div> <textarea value={messageText} onChange={(e) => setMessageText(e.target.value)} placeholder="输入消息内容..." style={{ width: '100%', height: 90, marginBottom: 12, padding: 8, borderRadius: 4, border: '1px solid #ddd' }} /> <div style={{ display: 'flex', gap: 10 }}> <button onClick={sendCustomMessageWithAttrs} disabled={!isConnected || !messageText.trim()} style={{ padding: '8px 18px', cursor: 'pointer', borderRadius: 4, border: 'none', backgroundColor: '#2563eb', color: 'white', opacity: !isConnected || !messageText.trim() ? 0.6 : 1 }} > 发送带自定义属性的消息 </button> <button onClick={sendCustomMessageWithExtension} disabled={!isConnected || !messageText.trim()} style={{ padding: '8px 18px', cursor: 'pointer', borderRadius: 4, border: 'none', backgroundColor: '#16a34a', color: 'white', opacity: !isConnected || !messageText.trim() ? 0.6 : 1 }} > 发送带自定义扩展的消息 </button> </div> </div> </div> ); }; export default XMPPChat;
关键说明:
- 两种自定义方式:
- 直接给
<message>加属性:适合简单的键值对数据,通过attrs参数传递,接收时直接从msg.attrs读取。 - 自定义扩展节点:适合复杂的嵌套数据,必须指定唯一的命名空间(避免和其他XMPP扩展冲突),用
stanza.io的xml方法构造节点,通过extensions参数传入,接收时用msg.getChild方法查找对应的节点。
- 直接给
- 注意事项:
- 一定要替换代码中的JID、密码、服务器地址和接收者JID为你的实际信息。
- 命名空间建议使用你自己的域名(比如
http://your-domain.com/xmpp/custom),确保唯一性。 - 发送前要检查连接状态和消息内容是否为空,避免无效调用。
内容的提问来源于stack exchange,提问作者For Guru
相关产品推荐
相关产品推荐

