消息计数、存储与推送策略
融云在「消息类型概述」中为每种消息类型定义了三个默认属性:是否计入会话未读、是否进入客户端本地存储与离线缓存、是否默认触发远程推送。本页给出完整矩阵,并说明本项目服务端的实际策略与差异。
先看结论
本项目没有 objectName,也没有按消息类型区分的计数/推送开关:所有落库的新消息(单聊/群聊/系统通知)统一计入接收方会话未读,聊天室消息不落库也不计未读;离线推送只有服务端 webhook,没有 APNs/FCM/厂商通道。未实现的部分请不要按融云默认值对外承诺。
融云默认策略矩阵(28 行)
| 消息类型 | objectName | 分类 | 计数与存储 | 离线缓存 | 默认推送 |
|---|---|---|---|---|---|
| 文本消息 | RC:TxtMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 高清语音消息 | RC:HQVCMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 图片消息 | RC:ImgMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| GIF 图片消息 | RC:GIFMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 图文消息 | RC:ImgTextMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 文件消息 | RC:FileMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 位置消息 | RC:LBSMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 小视频消息 | RC:SightMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 引用消息 | RC:ReferenceMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 合并转发消息 | RC:CombineMsg | 用户内容类 | 计入未读,客户端存储 | 支持 | 默认推送 |
| 撤回通知消息 | RC:RcNtf | 通知类 | 客户端存储,不计入未读 | 支持 | 默认不推送 |
| 提示条通知消息 | RC:InfoNtf | 通知类 | 客户端存储,不计入未读 | 支持 | 默认不推送 |
| 群组通知消息 | RC:GrpNtf | 通知类 | 客户端存储,不计入未读 | 支持 | 默认不推送 |
| 命令提醒消息 | RC:CmdNtf | 通知类 | 客户端存储,不计入未读 | 支持 | 默认不推送 |
| 正在输入状态消息 | RC:TypSts | 状态类 | 不存储,不计入未读 | 不支持 | 不支持推送 |
| 命令消息 | RC:CmdMsg | 信令类 | 不存储,不计入未读 | 支持 | 默认不推送 |
| 撤回命令消息 | RC:RcCmd | 信令类 | 不存储,不计入未读 | 支持 | 默认推送 |
| 单聊已读回执消息 | RC:ReadNtf | 信令类 | 不存储,不计入未读 | 支持 | 默认不推送 |
| 群聊已读回执请求消息 | RC:RRReqMsg | 信令类 | 不存储,不计入未读 | 支持 | 默认不推送 |
| 群聊已读回执响应消息 | RC:RRRspMsg | 信令类 | 不存储,不计入未读 | 支持 | 默认不推送 |
| 多端已读状态同步消息 | RC:SRSMsg | 信令类 | 不存储,不计入未读 | 支持 | 默认不推送 |
| 聊天室属性通知消息 | RC:chrmKVNotiMsg | 信令类 | 不存储,不计入未读 | 支持 | 默认不推送 |
| 实时音视频接受信令 | RC:VCAccept | 信令类 | 不存储,不计入未读 | 支持 | 默认推送 |
| 实时音视频挂断信令 | RC:VCHangup | 信令类 | 不存储,不计入未读 | 支持 | 默认推送 |
| 实时音视频邀请信令 | RC:VCInvite | 信令类 | 不存储,不计入未读 | 支持 | 默认推送 |
| 实时音视频切换信令 | RC:VCModifyMedia | 信令类 | 不存储,不计入未读 | 支持 | 默认推送 |
| 实时音视频成员变化信令 | RC:VCModifyMem | 信令类 | 不存储,不计入未读 | 支持 | 默认推送 |
| 实时音视频响铃信令 | RC:VCRinging | 信令类 | 不存储,不计入未读 | 支持 | 默认推送 |
补充口径(融云默认值):聊天室与超级群不支持离线缓存;Web 与小程序不支持客户端消息存储;通知类与状态类默认不推送;通知类若在发送时显式设置推送标题与内容,仍可触发推送。
本项目的计数与存储
| content.type | 计入未读 | 客户端存储(移动/桌面) | 服务端存储 | 离线补发 | 离线推送(webhook) |
|---|---|---|---|---|---|
text | 是 | 是 | 是 | 是 | 是 |
image | 是 | 是 | 是 | 是 | 是 |
file | 是 | 是 | 是 | 是 | 是 |
voice | 是 | 是 | 是 | 是 | 是 |
location | 是 | 是 | 是 | 是 | 是 |
custom | 是 | 是 | 是 | 是 | 是 |
recall | 否(替换原消息) | 是(占位) | 是(原地替换) | 是(原消息在离线队列时) | 否 |
system | 是(系统会话) | 是 | 是 | 是 | 否 |
- 未读由服务端在消息落库时对每个接收者 +1;发送者自己的其他端不计未读。@ 消息额外累计
mentionedCount。 - 撤回不新增消息:服务端把原消息内容替换为
recall占位,因此不会额外 +1 未读。 - 聊天室消息只在在线连接间广播,不落库、不补发;因此聊天室消息离线后不可恢复。
- 系统通知只允许服务端发往系统会话;当前不会触发离线推送 webhook。
本项目的离线与历史
| 项 | 本项目行为 |
|---|---|
| 服务端历史 | 消息写入 journal/状态并支持 message.history.get 分页(beforeSeq 向前翻页,默认 20、最大 100)。 |
| 离线队列 | 每会话最多 500 条;连接建立后按 seq 补发,客户端 ACK 推进游标。 |
| 聊天室 | 不落库、不补发;加入后最多获取最近 50 条(由聊天室语义决定)。 |
| 超级群 | conversationType=GROUP + groupType=super;持久化、支持离线与多端,但消息没有 channelId,频道级隔离未实现。 |
| 客户端本地存储 | 按平台实现;本项目 Web SDK 不做本地持久化,刷新后依赖服务端历史(与融云“Web 不保证本地存储”的结论一致)。 |
推送策略与差异
| 能力 | 融云默认 | 本项目当前 | 差异 |
|---|---|---|---|
| 用户内容类离线推送 | 默认推送,预置标题/内容 | 仅 webhook,需应用自行配置 | 无通道、无预置文案、无点击跳转 |
| 通知类推送 | 默认不推送,可自定义推送内容 | 不推送(通知类 objectName 未实现) | 无对应消息类型 |
| 状态类推送 | 不支持 | 不支持(输入状态走 WS 帧) | 一致 |
| 多设备推送 | 默认只推最后登录设备 | 无设备维度,webhook 按 userId 逐个投递 | 无 token 与设备表 |
| 推送内容 | 标题/内容/@ 文案优先级 | webhook 原样携带完整 message | 由应用自行构造系统通知 |
| 推送统计 | 控制台/统计接口 | push.log.list、push.stats.day、push.stats.by-id | 仅 webhook 投递统计 |
离线消息 webhook 的触发与载荷
当消息的接收者没有任何在线 WS 会话时,服务端会异步 POST 到应用配置的 webhook;超时 3 秒、失败只记日志、不阻塞投递、不做重试与签名。
JSON
{
"appkey": "demo",
"userId": "u2",
"reason": "offline",
"message": {
"messageId": "m_9f2a",
"conversationType": 1,
"targetId": "u2",
"senderId": "u1",
"seq": 42,
"timestamp": 1750000000000,
"direction": 2,
"content": {
"type": "text",
"text": "你好"
}
}
}配置入口是 Admin API POST /api/admin/apps/{appkey}/push(webhookUrl + enabled),不属于 Open API;完整接入步骤见 推送接入。
另外,push.send 可以按 all|tag|package|user|users 发送“不落地通知”,但它同样只是把载荷投递到同一个 webhook,并不是 APNs/FCM 通道。
推送内容与透传规则
| 项 | 融云规则 | 本项目当前 |
|---|---|---|
| 消息推送文案 | 发送消息时可传 pushContent(标题/内容);未传时用户内容类使用预置文案 | 消息接口没有 pushContent/pushData 参数;webhook 原样携带完整 message,由接收方生成文案 |
| @ 提及文案 | mentionedContent 优先级最高,覆盖默认/自定义 pushContent | mentionedInfo 只影响会话 mentionedCount 与客户端高亮;没有推送文案覆盖 |
| pushData 透传 | 随通知透传到客户端,用于点击后的业务路由 | 无通知载荷;webhook 的 message 可作为路由依据 |
| push.send extras | 随不落地通知透传 | extras 只进入 webhook 载荷与推送日志,不经过厂商通道 |
| 推送语言/模板 | 按客户端上报语言匹配模板 | 未实现(规划中) |
| 通知栏展示 | 标题、内容、图标、角标、分组 | 未实现;由 webhook 接收方自行调用系统/厂商 API |
| 鉴权与签名 | 应用配置与厂商凭证由服务端托管 | webhook 无签名、无鉴权头;接收方需自行限制来源 |
与融云的差异清单
- 封闭类型 vs objectName:本项目 ContentType 固定 8 值,新增消息类型必须改 IDL 与各端 SDK;融云可通过 objectName + 内容体扩展。
- 无按类型抑制计数:融云通知/状态/信令类有不同计数策略;本项目统一计数(撤回除外)。
- 撤回模型不同:本项目原地替换为
recall,融云生成RC:RcNtf通知消息与RC:RcCmd命令。 - 无远程推送通道:只有 webhook;没有 token 注册、厂商适配、点击跳转、角标、多语言模板。
- 无客户端消息存储策略差异:各端 SDK 自行决定本地库,服务端不区分类型。
- 超级群:本项目按普通群持久化,没有频道级计数/推送/历史隔离。
排期
消息类型扩展、推送通道、多端同步与按端已读、超级群客户端能力:均以本页标注的“未实现 / 部分实现”为准。
在对应条目完成前,以上“未实现”结论保持不变。
相关页面
融云原文(证据):/platform-chat-api/message-about/about-message-types