限制、错误码与重试规则
本页按当前聊天服务与客户端源码列出限制。数值是具体字段或路由的约束,不代表全局容量承诺;反向代理、操作系统和外部供应商还可能有独立限制,但本页不臆测未实现的策略。错误判断应结合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 的当前实现。本轮未执行生产业务请求或原生设备验收。