WebSocket 发送群消息
客户端通过 WebSocket 发送 sendGroupMessage 命令,服务端处理后将结果返回。
命令: sendGroupMessage
方向: 客户端 → 服务端 → 客户端
请求
message 字段支持 OneBot12 标准数组格式(兼容纯文本字符串):
{
"identifier": "req-001",
"command": "sendGroupMessage",
"groupId": 123456,
"groupType": 1,
"message": [
{"type": "text", "data": {"text": "hello world"}},
{"type": "image", "data": {"file_id": "abc123def456..."}},
{"type": "at", "data": {"qq": "3927731416"}}
]
}
| 字段 | 类型 | 说明 |
|---|---|---|
| identifier | string | 客户端自定义标识,服务端响应中原样返回,用于请求-响应匹配 |
| command | string | 固定值 "sendGroupMessage" |
| groupId | number | 目标群号 |
| groupType | number | 群类型,见下方 GroupType 表 |
| message | array | string | 消息内容。数组为 OneBot12 消息段,字符串兼容旧版纯文本 |
OneBot12 消息段
| type | data 字段 | 说明 |
|---|---|---|
text | text | 文本内容 |
image | file_id(文件 MD5) | 图片,需先通过桶上传接口上传 |
file | file_id(文件 MD5)、name(文件名) | 文件,需先通过桶上传接口上传 |
at | qq | @提及 QQ 号 |
图片/文件上传:通过
POST /external/api/v1/bucket/upload(multipart,file字段,≤100MB)上传到文件桶,获取file_id后填入消息段。详见下方示例。
GroupType 取值
| Code | 枚举 | 说明 |
|---|---|---|
| 0 | FAREAST_QQ_CHAT_GROUP | 远东官方 QQ 群(通过官方 bot 发送) |
| 1 | FAREAST_CHAT_GROUP | 远东内部群(直接入库) |
| 2 | FAREAST_PRIVATE_CHAT | 联系人/私聊(直接入库) |
| 3 | FAREAST_QQ_PRIVATE_CHAT | 远东官方 QQ 私聊 |
| 4 | SELF_QQ_CHAT_GROUP | 外部 QQ 群(通过私人 bot 发送) |
| 5 | SELF_QQ_PRIVATE_CHAT | 外部 QQ 私聊 |
成功响应
{
"type": "SendMessageResult",
"code": 200,
"identifier": "req-001",
"data": 1780651200000,
"msg": "success"
}
| 字段 | 说明 |
|---|---|
| type | "SendMessageResult" (code=2) |
| code | 200 表示成功 |
| identifier | 与请求中的 identifier 一致 |
| data | 消息创建时间戳 (ms) |
错误响应
缺少参数:
{
"type": "OperationFailed",
"code": 500,
"identifier": "req-001",
"msg": "缺少参数 groupId/groupType"
}
Bot 离线 (QQ 群):
{"type": "SendMessageResult", "code": 300, "msg": "QQ机器人离线,请稍后再试"}
用户不存在:
{"type": "OperationFailed", "code": 500, "identifier": "req-001", "msg": "用户不存在"}
未认证:
{"type": "LoginFail", "code": 400, "identifier": "req-001"}
处理流程
客户端 服务端
│ │
│── sendGroupMessage ──────────────→│
│ {identifier, groupId, │─ 验证连接已认证
│ groupType, message} │─ 解析 OneBot12 消息段
│ │─ 查 User 实体
│ │─ text → constructText
│ │─ image/file(file_id) → 桶消费 → constructImage/File
│ │─ at → constructAt
│ │─ groupMessageService.sendGroupMessage()
│ │ ├─ QQ 群: 通过 bot 发送
│ │ └─ 远东群: 直接入库
│ │─ 同步到其他群成员的 WebSocket
│←── SendMessageResult ─────────────│
│ {identifier, code, data} │
示例
JavaScript(OneBot12 文本)
const ws = new WebSocket("ws://ydzx.panretro.com/external/api/v1/im/imWebSocket/" + token);
ws.onopen = function() {
ws.send(JSON.stringify({
identifier: "msg-" + Date.now(),
command: "sendGroupMessage",
groupId: 123456,
groupType: 1,
message: [
{"type": "text", "data": {"text": "Hello from WebSocket!"}}
]
}));
};
ws.onmessage = function(event) {
const resp = JSON.parse(event.data);
if (resp.type === "SendMessageResult") {
if (resp.code === 200) {
console.log("发送成功, createTime:", resp.data);
} else {
console.error("发送失败:", resp.msg);
}
}
};
JavaScript(OneBot12 文本 + 图片,需先上传到桶)
function sendImage(file, text) {
// 1. 上传到文件桶
var fd = new FormData();
fd.append("file", file);
fetch("/external/api/v1/bucket/upload", {method: "POST", body: fd})
.then(r => r.json())
.then(resp => {
if (resp.code !== 200) { alert("上传失败"); return; }
// 2. 通过 WS 发送 file_id
var segments = [];
if (text) segments.push({"type": "text", "data": {"text": text}});
segments.push({"type": "image", "data": {"file_id": resp.data.file_id}});
ws.send(JSON.stringify({
identifier: "img-" + Date.now(),
command: "sendGroupMessage",
groupId: 123456,
groupType: 1,
message: segments
}));
});
}