WebSocket 接收消息推送
服务端在群内有新消息时,向该群所有在线成员的 WebSocket 连接推送消息更新。
消息类型: MessageUpdate
方向: 服务端 → 客户端(单向推送)
触发场景:
- 群内其他用户通过 HTTP 或 WebSocket 发送消息后,服务端调用
syncMessageToWebSocketClient()广播 - 不推送给发言人自己
推送格式
{
"type": "MessageUpdate",
"code": 1,
"data": {
"groupId": "123456",
"groupType": 1,
"userId": "1001",
"type": 1,
"content": "[{\"text\":{\"text\":\"hello\"}}]",
"pinyin": "[{\"text\":{\"text\":\"hello\"}}]",
"groupName": "测试群",
"groupNamePinyin": "ce4 shi4 qun2",
"messageId": "42",
"createTime": 1780651200000,
"receiveTime": "Fri Jun 14 20:30:00 CST 2026",
"nickname": "Alice",
"nicknamePinyin": "Alice",
"avatar": "/api/avatar/get/personal?id=1001"
}
}
data 字段 (FormatedMessageDto)
| 字段 | 类型 | 说明 |
|---|---|---|
| groupId | string | 群号(实际为 messageId) |
| groupType | number | 群类型代码 |
| userId | string | 发言人用户 ID |
| type | number | 消息类型,见 MessageType |
| content | string | 消息 JSON 内容 |
| messageId | string | 消息创建时间戳 |
| receiveTime | string | 格式化后的接收时间 |
| nickname | string | 发言人昵称(QQ 群为群名片,远东群为账号) |
| avatar | string/null | 发言人头像相对路径,详见 头像 API。无头像时为 null |
| pinyin | string | 消息内容的拼音版本,JSON 格式同 content,但 text 段中的中文已转为带数字声调的拼音 |
| groupName | string | 群组名称 |
| groupNamePinyin | string | 群组名称拼音(带数字声调) |
| nicknamePinyin | string | 发言人昵称拼音(带数字声调) |
MessageType 取值
| Code | 说明 |
|---|---|
| 0 | QQ_BOT_SYNC — QQ 机器人同步的消息 |
| 1 | FAREAST_TO_FAREAST — 远东内部消息 |
| 2 | FAREAST_TO_QQ — 远东发往 QQ |
| 3 | QQ_TO_FAREAST — QQ 发往远东 |
消息内容格式 (content)
content 为 JSON 数组,每个元素是一种消息段:
[
{"text": {"text": "hello world"}},
{"image": {"file": "abc123.jpg"}},
{"at": {"qq": "3927731416", "name": "Alice"}},
{"reply": {"id": "658617555", "messageId": "1783096941205"}}
]
| 类型 | 说明 |
|---|---|
text | 文本消息,data.text 为文本内容 |
image | 图片消息,data.file 为文件 ID |
at | @提及,data.qq 为 QQ 号,data.name 为昵称 |
reply | 回复消息,data.messageId 为被回复消息的真实 ID,data.id 仅供参考不可信 |
file | 文件消息,data.relativePath 为相对路径,data.isQQ 为 "1" 时代表 QQ 群文件。下载 URL:/downloadFile/{base64path}/{qq|local}/{safeName} |
客户端接收示例
const ws = new WebSocket("ws://ydzx.panretro.com/external/api/v1/im/imWebSocket/" + token);
ws.onmessage = function(event) {
const msg = JSON.parse(event.data);
if (msg.type === "MessageUpdate") {
const d = msg.data;
console.log(`[${d.nickname}] ${d.receiveTime}`);
console.log(d.content);
// 解析消息内容
const segments = JSON.parse(d.content);
segments.forEach(seg => {
if (seg.text) {
console.log(" text:", seg.text.text);
} else if (seg.image) {
console.log(" image:", seg.image.file);
} else if (seg.at) {
console.log(" @", seg.at.name);
}
});
}
};