常见问题与排查
先记录 SDK 版本、Node.js 版本、code、reason、op 和 requestId,再对照以下场景。错误提示文本不作为程序分支条件,示例见错误处理。
安装与运行
node --version
npm config get registry
npm view @deeprespond/im-server-sdk@1.0.0 version --registry=https://registry.npmjs.org/| 现象 | 处理 |
|---|---|
| npm 404 或 ETARGET | 包名为 @deeprespond/im-server-sdk,当前公开版本 1.0.0。私有镜像可能尚未同步,使用下方官方 registry 安装命令 |
| Unsupported engine | Node.js 至少为 22.17.0;在实际运行服务的容器或进程中检查版本 |
| Cannot use import outside a module | JavaScript 使用 .mjs,或在 package.json 中设置 type: module;CommonJS 使用 require() |
| 找不到示例中的 client.js | TypeScript 示例先按 NodeNext 编译,再运行生成的 JavaScript,见示例指南 |
| TypeScript 找不到子路径类型 | 使用 moduleResolution: NodeNext、node16 或 bundler;安装 @types/node@22,不要使用旧 node10 解析方式 |
| 浏览器或 Edge 中构造客户端失败 | 该包使用服务端凭据和 Node.js 能力;Next.js 路由配置 runtime = 'nodejs',网页改用客户端 Web SDK |
npm install @deeprespond/im-server-sdk@1.0.0 --registry=https://registry.npmjs.org/以上命令只为本次安装指定 registry,不修改项目或全局 npm 配置。
凭据与身份
| 名称 | 从哪里取得 | 用在哪里 |
|---|---|---|
AppKey:组织名 # 应用名 | 控制台应用信息 | 分别传给 orgName、appName |
| Client ID、Client Secret | 控制台服务端凭据 | 创建 DRClient,由 SDK 换取 App Token |
| App Token | SDK 自动换取、缓存和刷新 | 应用管理员身份调用 OpenAPI,不交给终端用户 |
| 用户登录凭证 ticket | 后端为已认证业务用户调用 users.issueLoginTicket() | 交给该用户的客户端 SDK 登录 |
| 回调 endpoint ID、签名密钥 | 控制台回调配置 | CallbackHandler.secrets,与 Client Secret 分开管理 |
服务端 SDK 具有应用管理权限。业务后端需要自己校验用户身份和操作权限,例如不能让请求中的任意 username 直接决定给谁签发 ticket;管理撤回和管理历史查询也不能直接当作普通用户接口。
鉴权与网络
| 现象 | 核对顺序 |
|---|---|
unauthenticated 或首次请求换令牌失败 | baseUrl 指向正确环境;组织名、应用名、Client ID/Secret 来自同一应用;凭据未被撤销;错误的 op 是否为 app.token |
client_unavailable | 查看 reason 和 details.cause;暂时故障可能处于冷却期。应用已删除或租户已注销时,isPermanentlyUnavailable 为 true,继续重试不能恢复 |
permission_denied | 核对应用状态、接口所需功能或策略,并按该 REST 接口的 details 排查 |
network_error | 检查目标域名、端口、容器网络、DNS、代理及证书链;不要把控制台网页地址误作 API 根地址 |
| HTTPS_PROXY 已设置但仍直连 | SDK 不自行读取环境代理,使用自定义 fetch/ProxyAgent;见代理与私有证书 |
| 私有 CA 证书校验失败 | 在启动进程前设置 NODE_EXTRA_CA_CERTS,保证证书文件在服务容器内可读;保留 TLS 校验 |
更新应用凭据时调用 im.updateCredentials(newClientId, newClientSecret),或更新配置并重启进程;不要在日志中打印 Secret、App Token、ticket 或带签名的下载地址。
超时、限流与重复操作
| 现象 | 含义与处理 |
|---|---|
timeout | 单次尝试或整次调用到期,或 AbortSignal.timeout() 触发。先核对 timeoutMs 与 totalTimeoutMs,两者均为毫秒 |
canceled | 调用方主动取消,或原客户端正在关闭;按业务需要终止本次流程 |
rate_limited | SDK 已按配置等待或达到等待上限。error.retryAfter 为秒;maxRetryAfterMs 为毫秒,不要混用 |
| 写请求超时后不知道是否成功 | 先查询服务端结果;同一业务重试复用消息 client_msg_id 或频道 operation_id,不要每次生成新值 |
| HTTP 成功但批量有失败 | 检查 result.ok、failed_items;调用 throwIfFailed() 可抛出 BatchError,逐项处理失败原因 |
version_conflict | 重新读取当前对象版本,再由业务决定是否更新;不要无条件覆盖并重复提交 |
isTemporary 表示错误通常可恢复,不表示任意写操作都可以安全重发。SDK 的自动重试分类见方法参考,业务任务重试仍需保持幂等标识。
回调接入
先完成“创建地址 → 启动接收端 → 验证地址”,再触发对应事件。服务端能够访问接收端地址才有效,本机浏览器能访问并不能证明远端可达。
| HTTP 状态或现象 | 排查 |
|---|---|
| 401 | endpoint ID、密钥数组、系统时间和原始请求体;同一个带签名请求重复发送会被防重放检查拒绝 |
| 400 | 签名通过但请求结构不符合协议;查看接收端日志,不把普通业务 JSON 直接发送到回调端点 |
| 413 | 同时检查反向代理、框架 body parser、SDK 的 maxBodyBytes;默认 SDK 上限为 2 MiB |
| 503 | 密钥查询、Redis 或业务处理失败,事件正在被另一实例处理,或同步回调超时;查看 handler 日志 |
| Express 验签失败 | 回调路由放在 express.json() 前,或保留原始 Buffer;不能把解析后的对象重新 JSON.stringify 代替原文 |
| Next.js 本地成功、线上重复处理 | 检查是否部署为多个实例;统一使用共享 Redis 和相同 keyPrefix,避免各实例只在内存去重 |
| 事件 204,但业务处理函数没运行 | 核对订阅和注册的事件名;未知事件或未注册的已知事件可能被忽略。需要统一观察时使用 onAny() |
| 同步回调 200,但预期策略没生效 | 检查返回的 SDK Verdict、实际启用的同步钩子和服务端配置;同步回调与事件订阅分开设置 |
回调有重投语义。业务写入成功后进程退出,仍可能再次收到同一事件;数据库写入或入队操作也应按事件 ID 幂等。共享存储和处理时限见接收回调。
文件与独立频道
上传时普通文件的内存来源需要 name,群文件需要 group_id,用户头像需要 owner。SDK 不支持以 Readable 流作为可重读的上传来源,先落盘或使用 Buffer/Blob。下载传媒体 url,SDK 负责换取临时下载地址,见文件上传与下载。
client.channels 管理独立 RTC 频道;client.calls 管理 IM 通话。创建频道、签发频道票据后,用户仍需通过对应客户端 API 加入媒体。频道分页使用 next_cursor,没有 channels.iter();修改频道和封禁操作所需的版本字段见频道参考。
提交排查信息
向运维或技术支持提供发生时间及其时区、环境、SDK/Node 版本、接口名、错误码和 requestId。附上经过脱敏的最小调用代码即可,保留实际字段名和超时配置;凭据和用户登录票据不随排查信息发送。
