WebSocket 查询群聊历史记录
通过 WebSocket 命令查询指定群组在某个时间点之前的消息记录,支持分页。
命令: fetchChatHistory
方向: 客户端 → 服务端 → 客户端
请求
{
"identifier": "req-001",
"command": "fetchChatHistory",
"groupId": 123456,
"groupType": 1,
"startDate": 42,
"pageSize": 20,
"belong": null
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| identifier | string | 是 | 客户端自定义标识,响应中原样返回 |
| command | string | 是 | 固定值 "fetchChatHistory" |
| groupId | number | 是 | 群号 |
| groupType | number | 是 | 群类型,参见 发送群消息 中的 GroupType 表 |
| startDate | number | 否 | 消息数据库 id 游标,查询此 id 之前的消息。默认:Long.MAX_VALUE(获取最新消息) |
| pageSize | number | 否 | 每页条数。默认:20 |
| belong | number | 否 | 外部机器人 QQ 号(外部 QQ 群)/ 私聊时服务端自动推导,无需传入 |
成功响应
{
"type": "FetchChatHistory",
"code": 3,
"identifier": "req-001",
"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"
},
{
"groupId": 123456,
"groupType": 1,
"userId": "1002",
"type": 1,
"content": "[{\"text\":{\"text\":\"hi\"}}]",
"pinyin": "[{\"text\":{\"text\":\"hi\"}}]",
"groupName": "测试群",
"groupNamePinyin": "ce4 shi4 qun2",
"messageId": 41,
"createTime": 1780651190000,
"receiveTime": "Fri Jun 14 20:29:00 CST 2026",
"nickname": "Bob",
"nicknamePinyin": "Bob",
"avatar": null
}
]
}
data 为 FormatedMessageDto 数组,按 create_time DESC 排序(最新在前)。
| 字段 | 类型 | 说明 |
|---|---|---|
| groupId | number | 群号 |
| groupType | number | 群类型代码 |
| userId | string | 发言人用户 ID |
| type | number | 消息类型 (MessageType) |
| content | string | 消息 JSON 内容,格式见 接收消息推送 |
| messageId | number | 消息 DB 主键 (id) |
| receiveTime | string | 格式化接收时间 |
| nickname | string | 发言人昵称(QQ 群为群名片,远东群为账号) |
| avatar | string/null | 发言人头像相对路径(QQ 用户: /api/avatar/get/QQpersonal?id={qq},远东用户: /api/avatar/get/personal?id={userId},无头像时为 null)。可在路径后追加 &size=aa 参数获取等比缩放到 aa 像素的图像 |
| pinyin | string | 消息内容的拼音版本,JSON 格式同 content,但 text 段中的中文已转为带数字声调的拼音 |
| groupName | string | 群组名称 |
| groupNamePinyin | string | 群组名称拼音(带数字声调) |
| nicknamePinyin | string | 发言人昵称拼音(带数字声调) |
错误响应
{"type": "OperationFailed", "code": 500, "identifier": "req-001", "msg": "缺少参数 groupId/groupType"}
翻页示例
首次请求不带 startDate(使用默认值 Long.MAX_VALUE),获取最新一批消息。每次取最后一条的 messageId(即数据库 id)作为下次的 startDate:
const ws = new WebSocket("ws://ydzx.panretro.com/external/api/v1/im/imWebSocket/via-cookie");
ws.onopen = function() {
// 查询最新 20 条
ws.send(JSON.stringify({
identifier: "fetch-1",
command: "fetchChatHistory",
groupId: 123456,
groupType: 1
}));
};
ws.onmessage = function(event) {
const resp = JSON.parse(event.data);
if (resp.type === "FetchChatHistory") {
const messages = resp.data;
const last = messages[messages.length - 1];
// 翻上一页
ws.send(JSON.stringify({
identifier: "fetch-2",
command: "fetchChatHistory",
groupId: 123456,
groupType: 1,
startDate: last.messageId // 以最后一条的 id 继续向前翻
}));
}
};