技术文档

限制、错误码与重试规则

本页按当前聊天服务与客户端源码列出限制。数值是具体字段或路由的约束,不代表全局容量承诺;反向代理、操作系统和外部供应商还可能有独立限制,但本页不臆测未实现的策略。错误判断应结合HTTP状态、error.code和当前业务阶段。

单位与计数

MiB=1048576字节,KiB=1024字节。界面显示“10 MB”时,当前服务实际检查10×1024×1024字节。JSON上限计算传输字节,包含字段名、引号、转义与base64膨胀;不能仅计算正文字符。base64约为原字节数的4/3,必须规范标准编码,base64url不适用MLS payload。

多数服务端文字使用[...text].length计Unicode码点;iOS的String.count计字素簇,Android的length/take计UTF-16代码单元。组合重音和多码点表情等会产生不同计数。客户端允许输入不代表服务端一定接受,应保留服务端错误说明。依据:chat-service/src/server.mjs:50-78,135-142、ios-app/Sources/Features/Moments/MomentComposerView.swift:97-100、android-app/app/src/main/java/cn/thestarline/workbench/MomentsScreens.kt:513-514。

服务端大小与数量

对象 实际限制 超限表现
默认JSON 16384字节,根必须对象 413 TOO_LARGE;非JSON为415 CONTENT_TYPE
普通消息 trim后文字≤2000码点;text与一个mediaId二选一 400 INVALID_MESSAGE
文件/聊天照片 单项10 MiB,非空 413 TOO_LARGE;空为400 EMPTY_FILE
自定义贴纸 512 KiB;PNG/JPEG;PNG宽高1–2048 INVALID_STICKER或TOO_LARGE
聊天媒体账号配额 合计100 MiB;自定义贴纸100个 413 STORAGE_LIMIT;没有公开清理媒体配额的DELETE接口
文件名 trim后1–120码点;无控制字符或路径分隔符 400 INVALID_NAME
新事 text≤2000码点;发布JSON≤20000字节;9图或单视频 400 INVALID_POST或413 TOO_LARGE
新事媒体 图片10 MiB、视频30 MiB;每账号500 MiB TOO_LARGE或STORAGE_LIMIT
简介/资料受众 bio≤160码点;selected最多100个不同当前好友 INVALID_BIO或INVALID_VIEWERS
个人群 name为1–40码点;创建/邀请1–49个不同好友;全群≤50人 INVALID_GROUP_NAME、INVALID_GROUP_MEMBERS或NOT_FRIENDS
新事评论/举报 评论1–500码点,举报1–200码点 INVALID_COMMENT或INVALID_REPORT
记忆识别 text为2–2000码点 INVALID_MEMORY_TEXT
MLS密钥包 TLS字节1–65536;JSON≤100000字节;每设备未用包≤25 INVALID_KEY_PACKAGE、TOO_MANY_PACKAGES或TOO_LARGE
MLS事件 payload 1–1048576字节;JSON≤1500000字节 INVALID_EVENT、INVALID_CIPHERTEXT或TOO_LARGE
iOS独立MLS文字 非空、≤65536 UTF-8字节 本地invalidState;不适用于普通消息接口

依据:chat-service/src/server.mjs:350-365,416-474,498-558,662-680,775-817,916-925、chat-service/src/database.mjs:219-226、chat-service/src/moments-repository.mjs:102-137、ios-app/Sources/Features/Chat/ChatCryptoDevice.swift:442-457。

分页、有效期与已有频率计数

类型 值与边界
单聊/群消息 默认50、最多100;limit最少1;before与非零after不能混用,群不支持单聊after契约
普通events 每批最多100,wait默认20秒、0–25秒;游标非负安全整数
MLS events 每批100、立即查询;sequence可合法跳号
新事feed 默认20、最多50;comments和notifications每页30
通话历史 最近100条终态;无公开该路由分页游标
原生登录/聊天ticket/session 10分钟/60秒/24小时;Account OIDC token期限另算
临时好友码/转出flow/媒体token 10分钟/5分钟/30秒
呼叫与空房 约60秒未接超时;默认每10秒检查媒体空房,连续空约90秒结束
未绑定新事媒体 超过24小时可清理,不是所有已发布媒体24小时到期

当前allowFriendLookup按用户+method维护10分钟固定窗口:phone与temporary-code各最多20次,generate-code最多10次,memory-recognition最多10次。窗口从该方法当前计数周期第一次请求起计算;达到上限后不会因持续失败自动延长窗口。格式验证失败一般在计数前拒绝;格式正确但查不到目标也会计数,模型调用开始后失败可能已经计数。

未见对普通messages发送、全部GET、群操作或新事发布统一应用此计数器,也没有该代码自动返回Retry-After或剩余额度头的契约。不能把10分钟20次写成全站限流。依据:chat-service/src/database.mjs:386-400、chat-service/src/server.mjs:775-790,832-898,1186-1190。

HTTP错误的触发条件

HTTP / error.code 典型触发条件 下一步
400 INVALID_JSON / INVALID_INPUT JSON无效、数组根、联系人添加方式不唯一、字段类型错误 修正请求结构,不能原样重试
400 INVALID_CURSOR / INVALID_LIMIT 非安全整数、负游标、数量为0、混合前后游标 使用正确资源游标;最少1条
400 INVALID_PHONE / INVALID_FRIEND_ID / INVALID_FRIEND_CODE 手机号、好友ID或临时码格式错误 本机规范化后再提交
400 INVALID_MESSAGE / INVALID_CLIENT_ID text和media互斥失败、文字过长、UUID不合规、read目标不属于聊天 修正字段,不生成空消息
400 INVALID_POST / INVALID_COMMENT 受众不符、媒体被绑定、图视频混传、回复不属于帖子 重读关系/资源;不要盲重发
400 NOT_FRIENDS 建群成员未满足好友条件;邀请成员也可因加入后超过50人失败 分别检查目标用户UUID、当前好友关系与群容量,不能仅按“已断交”解释
400 INVALID_LOCATION / 409 NOT_SHARING 坐标无效,或PUT前未开启共享 修正坐标;共享必须由用户显式开始
401 UNAUTHORIZED / INVALID_TICKET 聊天session失效,或ticket过期、重放、proof错误 重新登录;不能删除proof降级
403 CONTACT_BLOCKED / NOT_FRIENDS 联系动作中任一方屏蔽或当前不再是好友;建群/邀请的同码400例外见上行 刷新关系,停止发送/位置/通话动作
403 FORBIDDEN 非群主或非企业授权角色等 使用真实有权身份,不绕过UI校验
404 NOT_FOUND / PROFILE_NOT_FOUND / NOT_MEMBER 无记录、资源不可见、已退出范围等 刷新列表;不要枚举ID探测
409 CLIENT_ID_REUSED 同幂等ID改了范围、正文、媒体或MLS密文 恢复原请求;新用户动作才用新ID
409 ALREADY_FRIENDS / INCOMING_REQUEST 已有好友关系或反向申请 进入既有会话或接受incoming
409 E2EE_REQUIRED / NOT_ACTIVE 非legacy尝试普通发送,或MLS尚未激活 走正确协议并补必要确认,不退回明文
409 CALL_BUSY / CALL_STATE 另有通话或邀请、参与状态已变化 重查active/current,再决定动作
413 TOO_LARGE / STORAGE_LIMIT 单次请求过大或账号媒体配额满 减小输入;重试不增加可用配额
415 CONTENT_TYPE / 416 INVALID_RANGE JSON类型错误,或新事媒体Range语法/起止无效 改Content-Type或合法单段范围
429 TOO_MANY_LOOKUPS / TOO_MANY_CODES / TOO_MANY_RECOGNITIONS 对应用户method计数达到上限 停止密集重试,等该窗口结束
503 LOGIN_UNAVAILABLE / E2EE_UNAVAILABLE / CALL_MEDIA_UNAVAILABLE / MEMORY_MODEL_UNAVAILABLE / CITY_STICKER_UNAVAILABLE 缺配置、校验器/媒体/模型/素材不可用等 保留本机状态,检查具体依赖,适度重试
500 INTERNAL 未被路由映射的异常 保留脱敏上下文,先确认是否实际写入

MLS错误映射存在细节:NOT_MEMBER→404、UNKNOWN_DEVICE→403,INVALID_KEY_PACKAGE/INVALID_EVENT/INVALID_RECIPIENT/INVALID_WELCOME→400,其余具名错误通常409。因此INVALID_COMMIT当前是409,不能只按“INVALID前缀都400”分类;缺devices查询deviceId的INVALID_DEVICE为400,而包可用性内部的同名错误走409映射。依据:chat-service/src/server.mjs:1193-1203。

发送权限与历史读取权限并不对称。CONTACT_BLOCKED/NOT_FRIENDS约束相关发送、位置或通话动作,不能推导普通旧附件必然404;普通单聊媒体凭仍可见消息读取时没有重新查好友/屏蔽,所有者还可独立下载。新事媒体则重新按帖子可见性过滤。依据:chat-service/src/database.mjs:239-254、chat-service/src/moments-repository.mjs:117-123。

重试必须区分是否有幂等键

正常幂等例:普通消息POST使用相同clientId和相同内容,第一次响应丢失后重试返回200及原message;MLS沿用同clientId、同密文和同目标重试返回原sequence。不能重新加密后沿用旧ID。GET可恢复查询,已读只前进,PUT like设置同一状态可重复。

失败风险例:新事POST、评论POST与媒体上传没有同等clientId契约,响应丢失后直接重发可能重复内容或额外占用配额;先查询最新记录确认。生成好友码重试会替换旧码;申请接受重试可能因原申请已删除而404,此时应查会话而非认为好友建立必失败。换票响应丢失后ticket可能已消费,重试401需重新发起授权,不能恢复出未收到的token。

不要将401自动重试成无限登录循环,也不要把所有503视为无副作用:关系操作在媒体调用阶段失败与消息提交后刷新失败有不同边界。本机退出成功也不能证明远端logout成功;Account改密不自动撤销聊天session。依据:chat-service/src/database.mjs:524-551,635-652与登录与会话。

当前客户端差异

Android新事先选selected好友再切到其他visibility时,仍可能携带非空viewerIds,服务端返回400 INVALID_POST;iOS发布前在非selected时发送空列表。iOS独立MLS prepare遇blocked只返回模式,不自动完成重键,继续应用发送会因未active而拒绝。这些是本轮源码核出的失败路径,未运行或修复原生代码,不能标成验收通过。对应依据见新事和MLS协议。

客户端时限与验收

通用iOS JSON请求通常15秒、普通/events为32秒;聊天媒体60秒,新事媒体90秒。Android连接15秒,普通JSON读20秒、events读35秒、上传下载读90秒。它们是网络调用时限,不是文档或媒体预览的自动关闭时间,也不代表服务器一定在时限内取消已提交操作。依据:ios-app/Sources/Features/Chat/ChatAPI.swift:45-96、ios-app/Sources/Features/Moments/MomentsStore.swift:186-227、android-app/app/src/main/java/cn/thestarline/workbench/AppData.kt:26-94。

当前两端错误包装主要保留HTTP状态与message,并非都向业务层保留error.code;排错应记录已脱敏的状态、阶段与资源类型,不能记录Bearer、ticket、verifier或用户正文。字段全表见API参考,恢复步骤见故障处理,场景验证见验收矩阵。本轮为源码与文档核对,未执行生产业务或原生验收。

源码核对范围:2026-10-23 的当前实现。本轮未执行生产业务请求或原生设备验收。

Markdown 原文完整文档文本