Table of Contents
15.5 统一标记 IM 消息已读【未授权拦截通过,待登录态联调】
PATCH /tieup/api/v1/im/messages/read
鉴权:需要 Authorization: Bearer <access_token>。
请求体:
{
"read_scene": "artist_broadcast",
"message_uids": ["BCST-A9KJ-XXXX"]
}
粉丝读取偶像定向消息示例:
{
"read_scene": "artist_to_fan_direct",
"message_uids": ["ATFD-A9KJ-XXXX"]
}
偶像读取粉丝定向消息示例:
{
"read_scene": "fan_to_artist_direct",
"message_uids": ["FTAD-A9KJ-XXXX"]
}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
read_scene |
string | 是 | 已读场景:artist_to_fan_direct=粉丝读偶像定向消息,fan_to_artist_direct=偶像读粉丝定向消息,artist_broadcast=粉丝读偶像群发消息 |
message_uids |
array | 是 | 需要标记已读的融云消息 UID 列表,值来自历史消息的 messageUId,最少 1 条,最多 100 条 |
message_uids[] |
string | 是 | 融云消息 UID,最大 128 字符 |
响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
read_count |
integer | 本次实际新增已读数。定向消息为实际更新数;群发消息为 Redis 首次去重成功并投递队列的数量 |
queued_count |
integer | 本次投递群发已读落库队列的数量;定向消息固定为 0 |
响应示例:
{
"code": 200,
"message": "成功",
"data": {
"read_count": 1,
"queued_count": 1
}
}
群发已读开关关闭时,read_scene=artist_broadcast 的完整响应示例:
{
"code": 200,
"message": "成功",
"data": {
"read_count": 0,
"queued_count": 0
}
}
说明:关闭状态会在查询 message_uids 前直接返回;artist_to_fan_direct 和 fan_to_artist_direct 仍按原链路标记已读。
发送方已读回执格式
已读回执由服务端异步通过融云超级群定向消息 /message/ultragroup/publish.json 发送,自定义消息类型为 Tieup:ReadAck。阅读者是 fromUserId,原消息发送者是唯一的 toUserIds[],toGroupIds[] 是原消息所属超级群。回执固定使用 pushContent=""、isPersisted=0、isCounted=0,只做在线实时通知,不触发离线推送、不进入融云消息历史、不增加聊天未读数,也不再创建 APP 系统消息。
content JSON 字符串只保存展示文案;客户端所需的最小业务字段放在 extraContent JSON 字符串中,并设置 expansion=true。融云消息扩展是字符串 KV,因此 is_read、人数等值均为字符串。客户端必须注册超级群自定义类型 Tieup:ReadAck,从 SDK 消息的 expansionDic 读取扩展;SDK 外层 conversationType=10、targetId 已是原消息超级群,扩展中不重复传递群、频道或用户画像。
粉丝阅读偶像定向消息
read_scene=artist_to_fan_direct,通知接收方为偶像;只有偶像仍保持群聊页面心跳时才发送。
{
"fromUserId": "tieup_fan_10001",
"toGroupIds": ["tieup_artist_group_20001"],
"toUserIds": ["tieup_artist_20001"],
"objectName": "Tieup:ReadAck",
"content": "{\"content\":\"消息已读:粉丝已阅读您发送的定向消息\"}",
"pushContent": "",
"isPersisted": 0,
"isCounted": 0,
"expansion": true,
"extraContent": "{\"is_read\":\"true\",\"businessType\":\"im_direct_read_receipt\",\"messageUId\":\"ATFD-A9KJ-XXXX\",\"readAt\":\"2026-07-13 10:20:30\"}"
}
extraContent 反序列化结果:
{
"is_read": "true",
"businessType": "im_direct_read_receipt",
"messageUId": "ATFD-A9KJ-XXXX",
"readAt": "2026-07-13 10:20:30"
}
偶像阅读粉丝定向消息
read_scene=fan_to_artist_direct,阅读偶像作为发送者,原消息粉丝作为接收者,不受偶像群聊页面心跳限制。两类定向回执使用相同的最小扩展结构,客户端通过超级群消息的实际发送者和接收者判断方向。
{
"fromUserId": "tieup_artist_20001",
"toGroupIds": ["tieup_artist_group_20001"],
"toUserIds": ["tieup_fan_10001"],
"objectName": "Tieup:ReadAck",
"content": "{\"content\":\"消息已读:偶像已阅读您发送的定向消息\"}",
"pushContent": "",
"isPersisted": 0,
"isCounted": 0,
"expansion": true,
"extraContent": "{\"is_read\":\"true\",\"businessType\":\"im_direct_read_receipt\",\"messageUId\":\"FTAD-A9KJ-XXXX\",\"readAt\":\"2026-07-13 10:21:00\"}"
}
extraContent 反序列化结果:
{
"is_read": "true",
"businessType": "im_direct_read_receipt",
"messageUId": "FTAD-A9KJ-XXXX",
"readAt": "2026-07-13 10:21:00"
}
粉丝阅读偶像群发消息
read_scene=artist_broadcast,通知接收方为偶像。立即通知使用当前有效阅读粉丝作为发送者;尾部通知使用窗口内最新有效阅读粉丝。同一原群发消息默认每 60 秒最多触达一次,任务执行时偶像必须仍保持群聊页面心跳。
{
"fromUserId": "tieup_fan_10001",
"toGroupIds": ["tieup_artist_group_20001"],
"toUserIds": ["tieup_artist_20001"],
"objectName": "Tieup:ReadAck",
"content": "{\"content\":\"群发消息已读:您的群发消息已有 328/1000 位粉丝阅读\"}",
"pushContent": "",
"isPersisted": 0,
"isCounted": 0,
"expansion": true,
"extraContent": "{\"businessType\":\"im_broadcast_read_receipt\",\"messageUId\":\"BCST-A9KJ-XXXX\",\"readAt\":\"2026-07-13 10:22:00\",\"readCount\":\"328\",\"targetCount\":\"1000\"}"
}
extraContent 反序列化结果:
{
"businessType": "im_broadcast_read_receipt",
"messageUId": "BCST-A9KJ-XXXX",
"readAt": "2026-07-13 10:22:00",
"readCount": "328",
"targetCount": "1000"
}
回执字段:
| 字段 | 类型 | 说明 |
|---|---|---|
is_read |
string | 仅定向回执提供,固定为字符串 "true" |
businessType |
string | 定向回执为 im_direct_read_receipt,群发回执为 im_broadcast_read_receipt |
messageUId |
string | 原消息融云 UID,与历史接口返回字段一致 |
readAt |
string | 本次回执发送者首次阅读原消息的时间 |
readCount |
string | 仅群发回执提供,当前最新已落库人数 |
targetCount |
string | 仅群发回执提供,原群发消息目标人数 |
说明:
- 本接口替代旧版
PATCH /tieup/api/v1/artists/{artist_id}/messages/read和PATCH /tieup/api/v1/artist/fans/{fan_user_id}/messages/read。 - 当前历史消息列表接口已在服务端自动兼容已读处理:粉丝拉取
GET /tieup/api/v1/artists/{artist_id}/messages时会自动处理本页偶像定向和偶像群发消息,偶像拉取GET /tieup/api/v1/artist/messages时会自动处理本页粉丝定向消息。本接口继续保留,作为客户端显式补偿或旧版本兼容入口。 - 服务端按当前 Token 的
current_identity校验使用端:粉丝端只能上报artist_to_fan_direct和artist_broadcast;偶像端只能上报fan_to_artist_direct。 - 本接口只接受
message_uids,不再接受旧参数message_nos;未知、无权限、方向不匹配或当前用户不可见的 UID 不会被处理,也不会泄露消息是否存在。 - 定向消息已读沿用原有事务逻辑,重复标记不会重复扣减未读数。
- 群发消息已读先使用 Redis Set 快速去重并投递队列,队列异步写入
tieup_im_broadcast_read_receipt,再推进tieup_im_message_stat.read_count和tieup_artist_broadcast_task.read_count。 - 群发已读仅允许当前仍处于该偶像有效订阅中的粉丝上报;过期订阅粉丝不会计入本次已读。
- 粉丝首次阅读偶像定向消息时,只有该偶像仍在群聊页面才由阅读粉丝向原发送偶像发送
Tieup:ReadAck超级群定向回执;偶像不在页面时只保存已读事实。 - 偶像首次阅读粉丝定向消息时,由阅读偶像向原发送粉丝发送
Tieup:ReadAck超级群定向回执,不受偶像群聊页面心跳限制。 - 粉丝首次阅读偶像群发消息后继续按原消息聚合人数;立即通知使用当前阅读粉丝,尾部通知使用窗口内最新有效阅读粉丝作为回执发送者,同一粉丝重复上报不会重复计数。
- 群发聚合通知默认每 60 秒最多触达一次。窗口内新增已读由尾部延迟任务通知最新已落库人数;任务执行时偶像已离开群聊页面则直接跳过且不补发。
- 群发窗口阅读者使用 Redis ZSet 按
read_at保存,默认 TTL 为 180 秒;Redis 数据缺失时按tieup_im_broadcast_read_receipt(message_no, read_at)索引查询最新阅读者兜底,MySQL 明细仍是最终事实。 - 已读回执固定
pushContent=""、isPersisted=0、isCounted=0,只在线实时送达,不触发离线推送、不进入融云历史、不增加聊天未读,也不写入 APP 系统消息表;定向已读事实保存在原消息记录,群发事实保存在群发已读明细表。 - 群发已读落库及通知使用独立异步队列,避免高峰积压影响定向已读和其他公共异步业务。