Files
open-im-server-deploy/docs/redpacket-message-structure.md
kim.dev.6789 e50142a3b9 复制项目
2026-01-14 22:16:44 +08:00

290 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 红包消息结构文档
## 客户端收到的推送消息结构
### 完整消息结构 (MsgData)
客户端通过WebSocket或HTTP拉取收到的红包消息消息结构如下
```json
{
"clientMsgID": "client_1234567890abcdef", // 客户端消息IDstring
"serverMsgID": "msg_1234567890abcdef", // 服务器消息IDstring
"sendID": "user_owner123", // 发送者ID群主IDstring
"recvID": "", // 接收者ID群消息为空string
"groupID": "group123", // 群IDstring
"senderPlatformID": 0, // 发送者平台IDint320表示系统
"senderNickname": "群主昵称", // 发送者昵称string
"senderFaceURL": "https://...", // 发送者头像URLstring
"sessionType": 3, // 会话类型int323-群聊
"msgFrom": 200, // 消息来源int32200-系统消息
"contentType": 110, // 消息类型int32110-自定义消息
"content": "{\"data\":\"{\\\"redPacketID\\\":\\\"rp_123\\\",\\\"redPacketType\\\":1,\\\"blessing\\\":\\\"恭喜发财\\\"}\",\"description\":\"redpacket\",\"extension\":\"\"}", // 消息内容JSON字符串自定义消息格式
"seq": 123456, // 消息序号int64
"sendTime": 1704067200000, // 发送时间戳int64毫秒
"createTime": 1704067200000, // 创建时间戳int64毫秒
"status": 2, // 消息状态int322-发送成功
"isRead": false, // 是否已读bool
"options": { // 消息选项map[string]bool
"history": true, // 是否保存历史
"persistent": true, // 是否持久化
"offlinePush": true, // 是否离线推送
"unreadCount": true, // 是否计入未读数
"conversationUpdate": true, // 是否更新会话
"senderSync": true // 是否同步给发送者
},
"offlinePushInfo": { // 离线推送信息(可选)
"title": "[HONGBAO]", // 推送标题
"desc": "[HONGBAO]", // 推送描述
"ex": "", // 扩展字段
"iosPushSound": "", // iOS推送声音
"iosBadgeCount": false // iOS角标计数
},
"atUserIDList": [], // @用户列表string[]
"attachedInfo": "", // 附加信息string
"ex": "" // 扩展字段string
}
```
### Content字段解析
`content` 字段是一个JSON字符串需要先解析为 `CustomElem` 结构(自定义消息格式),然后从 `data` 字段中解析出 `RedPacketElem` 结构:
#### CustomElem 结构(自定义消息外层结构)
```json
{
"data": "{\"redPacketID\":\"rp_123\",\"redPacketType\":1,\"blessing\":\"恭喜发财\",\"isReceived\":false,\"receiveInfo\":null}", // 红包数据的JSON字符串string必填
"description": "redpacket", // 二级类型标识string"redpacket"表示红包消息
"extension": "" // 扩展字段string可选
}
```
#### RedPacketElem 结构从data字段中解析
```json
{
"redPacketID": "rp_1234567890abcdef", // 红包IDstring必填
"redPacketType": 1, // 红包类型int32必填1-普通红包2-拼手气红包
"blessing": "恭喜发财", // 祝福语string可选
"isReceived": false, // 当前用户是否已领取bool服务器填充
"receiveInfo": null // 领取信息RedPacketReceiveInfo仅拼手气红包且已领取时返回
}
```
#### RedPacketReceiveInfo 结构(领取信息)
```json
{
"amount": 1000, // 领取金额int64单位
"receiveTime": 1704067200000, // 领取时间戳int64毫秒
"isLucky": false // 是否为手气最佳bool仅拼手气红包有效
}
```
#### 字段说明
| 字段名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `redPacketID` | string | 是 | 红包唯一标识用于后续领取、查询等操作总金额、总个数等信息可通过红包ID查询获取 |
| `redPacketType` | int32 | 是 | 红包类型1-普通红包平均分配2-拼手气红包(随机分配) |
| `blessing` | string | 否 | 祝福语 |
| `isReceived` | bool | 是 | 当前用户是否已领取服务器根据用户ID自动填充 |
| `receiveInfo` | RedPacketReceiveInfo | 否 | 领取信息,仅当 `isReceived=true``redPacketType=2`(拼手气红包)时返回 |
#### receiveInfo 字段说明
| 字段名 | 类型 | 说明 |
|--------|------|------|
| `amount` | int64 | 领取金额,单位:分 |
| `receiveTime` | int64 | 领取时间戳,毫秒 |
| `isLucky` | bool | 是否为手气最佳(仅拼手气红包有效) |
### 消息类型常量
- **ContentType**: `110` (`constant.Custom` - 自定义消息)
- **二级类型标识**: `"redpacket"` (存储在 `CustomElem.description` 字段中)
- **SessionType**: `3` (`constant.ReadGroupChatType` - 群聊)
- **MsgFrom**: `200` (`constant.SysMsgType` - 系统消息)
### 客户端解析示例
#### JavaScript/TypeScript
```typescript
interface RedPacketReceiveInfo {
amount: number; // 领取金额(分)
receiveTime: number; // 领取时间戳(毫秒)
isLucky: boolean; // 是否为手气最佳
}
interface RedPacketElem {
redPacketID: string;
redPacketType: number; // 1-普通红包2-拼手气红包
blessing?: string;
isReceived: boolean; // 当前用户是否已领取
receiveInfo?: RedPacketReceiveInfo; // 领取信息(仅拼手气红包且已领取时返回)
}
interface CustomElem {
data: string; // 红包数据的JSON字符串
description: string; // 二级类型标识:"redpacket"
extension?: string; // 扩展字段
}
interface RedPacketMessage {
clientMsgID: string;
serverMsgID: string;
sendID: string;
groupID: string;
contentType: number; // 110 (自定义消息)
content: string; // CustomElem的JSON字符串
sendTime: number;
// ... 其他字段
}
// 解析消息
function parseRedPacketMessage(msg: RedPacketMessage): RedPacketElem | null {
// 检查是否为自定义消息类型
if (msg.contentType !== 110) {
return null;
}
try {
// 先解析自定义消息结构
const customElem: CustomElem = JSON.parse(msg.content);
// 检查二级类型是否为红包
if (customElem.description !== "redpacket") {
return null;
}
// 从data字段中解析红包数据
const redPacketElem: RedPacketElem = JSON.parse(customElem.data);
return redPacketElem;
} catch (e) {
console.error('Failed to parse red packet content:', e);
return null;
}
}
```
#### Go
```go
type RedPacketReceiveInfo struct {
Amount int64 `json:"amount"` // 领取金额(分)
ReceiveTime int64 `json:"receiveTime"` // 领取时间戳(毫秒)
IsLucky bool `json:"isLucky"` // 是否为手气最佳
}
type RedPacketElem struct {
RedPacketID string `json:"redPacketID"`
RedPacketType int32 `json:"redPacketType"`
TotalAmount int64 `json:"totalAmount"`
TotalCount int32 `json:"totalCount"`
Blessing string `json:"blessing"`
IsReceived bool `json:"isReceived"` // 当前用户是否已领取
ReceiveInfo *RedPacketReceiveInfo `json:"receiveInfo,omitempty"` // 领取信息(仅拼手气红包且已领取时返回)
}
type CustomElem struct {
Data string `json:"data"` // 红包数据的JSON字符串
Description string `json:"description"` // 二级类型标识:"redpacket"
Extension string `json:"extension"` // 扩展字段
}
func ParseRedPacketContent(content []byte) (*RedPacketElem, error) {
// 先解析自定义消息结构
var customElem CustomElem
if err := json.Unmarshal(content, &customElem); err != nil {
return nil, err
}
// 检查二级类型是否为红包
if customElem.Description != "redpacket" {
return nil, fmt.Errorf("not a red packet message")
}
// 从data字段中解析红包数据
var redPacketElem RedPacketElem
if err := json.Unmarshal([]byte(customElem.Data), &redPacketElem); err != nil {
return nil, err
}
return &redPacketElem, nil
}
```
### 完整消息示例
```json
{
"clientMsgID": "client_1704067200000_abc123",
"serverMsgID": "msg_1704067200000_def456",
"sendID": "user_owner123",
"recvID": "",
"groupID": "group123",
"senderPlatformID": 0,
"senderNickname": "群主",
"senderFaceURL": "https://example.com/avatar.jpg",
"sessionType": 3,
"msgFrom": 200,
"contentType": 110,
"content": "{\"data\":\"{\\\"redPacketID\\\":\\\"rp_1234567890abcdef\\\",\\\"redPacketType\\\":1,\\\"blessing\\\":\\\"恭喜发财\\\",\\\"isReceived\\\":false,\\\"receiveInfo\\\":null}\",\"description\":\"redpacket\",\"extension\":\"\"}",
"seq": 123456,
"sendTime": 1704067200000,
"createTime": 1704067200000,
"status": 2,
"isRead": false,
"options": {
"history": true,
"persistent": true,
"offlinePush": true,
"unreadCount": true,
"conversationUpdate": true,
"senderSync": true
},
"offlinePushInfo": {
"title": "[HONGBAO]",
"desc": "[HONGBAO]"
},
"atUserIDList": [],
"attachedInfo": "",
"ex": ""
}
```
### 消息选项说明
| 选项名 | 说明 |
|--------|------|
| `history` | 是否保存到历史记录 |
| `persistent` | 是否持久化存储 |
| `offlinePush` | 是否离线推送 |
| `unreadCount` | 是否计入未读数 |
| `conversationUpdate` | 是否更新会话 |
| `senderSync` | 是否同步给发送者 |
### 注意事项
1. **Content字段**: 是JSON字符串需要先解析为 `CustomElem` 结构,然后从 `data` 字段中解析 `RedPacketElem`
2. **消息类型**: 使用自定义消息类型(`contentType = 110`),通过 `description` 字段标识二级类型为 `"redpacket"`
3. **二级类型扩展**: 未来可以扩展其他自定义消息类型,只需在 `description` 字段中使用不同的标识(如 `"wallet"``"coupon"` 等)
4. **金额单位**: `receiveInfo.amount` 单位是"分",不是"元"
5. **总金额和总个数**: 不在消息中传递,客户端可通过 `redPacketID` 调用查询接口获取详细信息
5. **红包类型**:
- `1` = 普通红包(平均分配)
- `2` = 拼手气红包(随机分配)
6. **发送者**: 固定为群主,`sendID` 为群主ID
7. **消息来源**: `msgFrom = 200` 表示系统消息
8. **会话类型**: `sessionType = 3` 表示群聊
9. **领取状态**: `isReceived` 字段由服务器根据当前用户ID自动填充客户端无需设置
10. **领取信息**: `receiveInfo` 仅在以下情况返回:
- `isReceived = true`(用户已领取)
- `redPacketType = 2`(拼手气红包)
- 普通红包(`redPacketType = 1`)即使已领取也不会返回 `receiveInfo`
11. **客户端存储**: 客户端收到消息后,应将 `isReceived``receiveInfo` 存储到本地用于UI展示
12. **兼容性**: 使用标准自定义消息类型无需修改客户端SDK只需在客户端添加红包消息的解析逻辑