WebSocket 协议参考
本页由 IDL protocol.json 自动生成,描述长连接的传输、帧结构、时序、可靠性与限制。
传输
| 项 | 值 |
|---|---|
| 连接路径 | /ws |
| 查询参数 | token、appkey |
| 帧编码 | json-utf8 |
| 单帧上限 | 65536 字节 |
| 服务端推送 | 无 id,客户端按 type 分发 |
帧结构
{
"id": "string?",
"type": "string",
"data": "object"
}上行帧(客户端 → 服务端)
共 10 种帧;每帧的 type 为唯一分派键,data 字段由下方表格逐个列出。
ping
心跳;服务端记录 session 活跃(起始版本 1.0.0)
该帧无 data 字段。
响应帧:pong
send
发送消息。会话类型决定目标校验:PRIVATE=对端 userId;GROUP=groupId(含超级群);CHATROOM=chatroomId(需先 chatroom_join);SYSTEM 禁止客户端发送。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
clientMsgId | string?(幂等键,10 分钟内同用户重复使用返回首次结果) |
conversationType | ConversationType |
targetId | string |
content | Content |
响应帧:send_ack
ack
客户端持久化成功后上行确认;服务端推进该用户会话 deliveredSeq。不 ACK 的消息在重连时重放(至少一次)。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
messageId | string |
响应帧:ack_ok
read
清未读(可带 seq,缺省表示清空到最新)。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
conversationType | ConversationType |
targetId | string |
seq | uint64? |
响应帧:read_ok
read_receipt
已读回执;服务端记录唯一读者并推送给消息发送者。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
conversationType | ConversationType |
targetId | string |
messageIds | string[] |
响应帧:read_receipt_ack
recall
撤回本人消息,时限 recallWindowMs。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
messageId | string |
响应帧:recall_ack
typing
正在输入;不持久化、不校验禁言。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
conversationType | ConversationType |
targetId | string |
typing | bool |
响应帧:typing_ack
sync
主动补拉(预留);cursor 形如 [{conversationType,targetId,seq}]。缺省按服务端游标全量补拉。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
cursor | object? |
响应帧:sync_done
chatroom_join
加入聊天室(幂等);成功后服务端向房内广播 chatroom_event(member_changed)。聊天室消息不落离线。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
chatroomId | string |
响应帧:chatroom_joined
chatroom_leave
离开聊天室;断连时服务端自动移除并广播。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
chatroomId | string |
响应帧:chatroom_left
下行帧(服务端 → 客户端)
共 24 种帧;每帧的 type 为唯一分派键,data 字段由下方表格逐个列出。
hello
建连成功;随后推送离线消息,最后 sync_done。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
userId | string |
sessionId | string |
serverTime | int64 |
syncState | {conversations:[{conversationType,targetId,deliveredSeq}]}? |
message
收到新消息/离线补发/多端同步副本(direction 标识)。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
message | Message |
send_ack
发送成功回执。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
id | string? |
clientMsgId | string |
messageId | string |
seq | uint64 |
timestamp | int64 |
ack_ok
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
messageId | string |
read_ok
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
conversationType | ConversationType |
targetId | string |
read_receipt
推送给消息发送者;含 readCounts/totalMembers。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
0 | R |
1 | e |
2 | a |
3 | d |
4 | R |
5 | e |
6 | c |
7 | e |
8 | i |
9 | p |
10 | t |
read_receipt_ack
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
messageIds | string[] |
readCounts | map |
totalMembers | uint32? |
recall
广播撤回后的完整消息(content.type=recall)。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
message | Message |
recall_ack
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
messageId | string |
message | Message |
typing
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
conversationType | ConversationType |
targetId | string |
userId | string |
typing | bool |
timestamp | int64 |
typing_ack
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
typing | bool |
sync_done
离线/补拉推送完毕。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
count | uint32 |
pong
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
serverTime | int64 |
friend_event
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
kind | FriendEventKind |
request | FriendRequest? |
fromUserId | string? |
toUserId | string? |
timestamp | int64 |
chatroom_joined
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
chatroom | Chatroom |
members | ChatroomMember[]? |
chatroom_left
—(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
chatroomId | string |
chatroom_event
聊天室成员变化/销毁广播(房内在线成员)。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
chatroomId | string |
kind | ChatroomEventKind |
userId | string? |
onlineCount | uint32? |
chatroom | Chatroom? |
timestamp | int64 |
kick
服务端强制断开(封禁/管理员踢下线)。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
code | int |
reason | string |
error
请求错误回显(带请求 id)或连接级错误。(起始版本 1.0.0)
| 字段 | 类型 |
|---|---|
code | int |
message | string |
reaction_changed
消息回应变更广播(推送给会话参与者,含操作者自身多端)。(起始版本 1.1.0)
| 字段 | 类型 |
|---|---|
messageId | string |
conversationType | ConversationType |
targetId | string |
reactionId | string |
operation | added|removed|cleared |
userId | string |
reactionTime | int64 |
totalCount | uint32 |
users | string[]? |
expansion_changed
消息扩展变更广播(推送给会话参与者,含操作者自身多端)。(起始版本 1.1.0)
| 字段 | 类型 |
|---|---|
messageId | string |
conversationType | ConversationType |
targetId | string |
updated | map |
removed | string[]? |
timestamp | int64 |
status
状态消息/信令转发(输入中、已读等):由 Open API statusmessage.private/group.publish 触发,仅投递在线会话,不落库。(起始版本 1.1.0)
| 字段 | 类型 |
|---|---|
statusMessage | [object Object] |
stream_changed
流式消息增量/结束广播(IDL rev17):客户端 REST `POST .../messages/stream/append` 与 `.../stream/end` 触发,推送给会话全部在线参与者(单聊双方与发送者其它端、群成员、聊天室已加入用户);`text` 为累计全文,`complete=true` 表示已结束(此时普通消息已按预分配 messageId 落库,客户端据此收敛)。(起始版本 1.2.0)
| 字段 | 类型 |
|---|---|
streamId | string |
messageId | string |
conversationType | ConversationType |
targetId | string |
senderId | string |
delta | string |
seq | uint32 |
text | string |
status | streaming|ended |
complete | bool |
timestamp | int64 |
presence_changed
实时在线状态变更(IDL rev20):用户上线(首条会话建立,reason=connect)、离线(最后一条会话关闭,reason=disconnect)、被踢下线(封禁/管理员踢下线,reason=kick)、账号注销(reason=deactivate)时推送。接收者 = 该用户的好友(双向,默认订阅)+ 显式订阅了该用户在线状态的用户(`POST .../users/{userId}/presence/subscriptions`),两者并集去重且排除本人;无接收者时服务端静默不下发。同账号第 2..N 条会话建立只通知本人其它端(不向好友重复推 online=true),中间会话关闭不产生帧。`online=true` 时 `lastSeenAt` 为本次上线时间;`online=false` 时 `lastSeenAt` 为本次离线时间(服务端不维护历史最后在线时间,故与 `timestamp` 相等)。客户端应按 `userId` 覆盖本地在线态,不依赖到达顺序。(起始版本 1.4.0)
| 字段 | 类型 |
|---|---|
userId | string |
online | bool |
lastSeenAt | int64 |
timestamp | int64 |
reason | connect|disconnect|kick|deactivate |
时序
connect
1. WS open
2. server hello
3. server message* (offline replay, seq 升序)
4. server sync_done
5. client 开始 ping/pong
6. SDK 触发 CONNECTEDsend
1. client send(id)
2. server 校验/持久化/分配 seq
3. client send_ack(id)
4. server 扇出 message 给接收方在线会话 + 发送者其他端
5. 接收端持久化后 ackofflineReplay
1. 服务端按 user+conversation 的 deliveredSeq 重放 seq>deliveredSeq 的消息
2. 客户端 ack 后推进
3. 重放受 offlineMaxPerConversation 限制,超出提示客户端走 REST 历史拉取multiDevice
1. 同账号所有在线会话均收到消息副本
2. 发送端其他端 direction=SEND 且 clientMsgId 相同
3. 接收端 direction=RECEIVE
4. 任一端 ack 推进用户级游标(已知限制:非端级游标,v1.1 可升级)chatroom
1. client chatroom_join
2. server chatroom_joined + 房内广播 chatroom_event(member_changed)
3. client send(conversationType=3)
4. server 广播给房内在线成员(不持久化、不补发)
5. client chatroom_leave / 断连 → chatroom_event(left)可靠性
- 投递语义:at-least-once(客户端按 messageId 去重)
- 幂等(send):同用户 clientMsgId 10 分钟内幂等
- 幂等(chatroom_join):幂等
- 幂等(ack):幂等
- 去重:客户端必须按 messageId 去重;服务端按 clientMsgId 去重
- 顺序:同一会话内 seq 单调递增;跨会话无全局序
- ack 推进:仅当 ack 的 messageId 属于当前用户可达消息时推进游标;乱序 ack 取已确认最大连续 seq
- 故障恢复:服务端重启后内存会话游标丢失时,以持久化消息与客户端 seq 补拉恢复(v1.0.0 演示实现:内存态+可选 PostgreSQL)
限制
| 限制项 | 值 |
|---|---|
messageBytes | 5120 |
textChars | 5000 |
offlineMaxPerConversation | 500 |
historyPageDefault | 20 |
historyPageMax | 100 |
groupMaxMembers | 3000 |
superGroupMaxMembers | 100000 |
chatroomMaxOnline | 5000 |
recallWindowMs | 120000 |
typingRatePerMinute | 60 |
sendRatePerMinute | 120 |
presenceBatchMax | 100 |
presenceSubscriptionsMax | 500 |
readUsersPageDefault | 50 |
combineTitleChars | 64 |
combineItemsMax | 100 |
combineTextBytes | 16384 |