OpenAPI 与 Postman 调试
本页给出由 IDL 自动导出的 OpenAPI 3.1 描述与 Postman v2.1 集合:两者都包含全部 230 个 Open API 操作、统一响应包络与签名头,随文档构建重新生成。第一次调试建议先跑通本页的 Node 脚本,再导入 Postman 批量试接口。
概念
| 导出物 | 路径 | 格式 | 用途 |
|---|---|---|---|
| OpenAPI 描述 | docs-site/assets/openapi-v1.json | OpenAPI 3.1.0 | 导入 Apifox / Swagger UI / Postman / 代码生成器 |
| Postman 集合 | docs-site/assets/postman-collection.json | Postman Collection v2.1 | 按能力分文件夹批量调试,内置自动签名脚本 |
签名算法与服务端实现完全一致:Signature = hex(sha1(AppSecret + Nonce + Timestamp))(小写)。以 AppSecret=demo-secret、Nonce=9f2a7c1b、Timestamp=1750000000000 为例,签名为 372e885320aabd997aafc5491f9d90fdca94432e。
两个 JSON 都由文档平台在发布时自动重写;直接编辑会在下次发布被覆盖,且零漂移校验会判定生成物过期。
前置条件
- 服务端已启动(默认
http://127.0.0.1:8080;IM_ADDR可改)。 - 已创建应用并拿到 AppKey / AppSecret(AppSecret 仅创建或重置时返回)。
- 本机 Node.js 18+(脚本使用内置
fetch)或 Postman v10+。 - 文档已构建过至少一次,
docs-site/assets/下存在两个导出文件。
步骤
- 获取导出物
从本页上方链接下载
openapi-v1.json与postman-collection.json;它们随每次发布自动刷新,与当前契约一致。 - 直接用 Node 调通一个接口
运行下方「签名与调用」脚本;先
user.register再user.get,两次都应返回code=0。 - 导入 Postman 集合
Postman → Import → 选择
postman-collection.json;左侧出现「NI PaaS IM Open API」集合,按能力分为用户/消息/群组等文件夹。集合级 Pre-request Script 会自动写入
nonce、timestamp、signature三个集合变量,无需手工计算。 - 设置集合同变量
在集合的 Variables 页把
host、appKey、appSecret改为自己的值;host不带/im/v2(请求路径会自动拼接)。也可以新建环境并导入下方环境 JSON,效果相同。
- 发送请求
选「用户 → 注册用户」,Body 已是脚本生成的示例 JSON,点击 Send。
返回
{"code":0,"data":{...},"requestId":"..."}即成功;401/403 见下方常见问题。 - 导入 OpenAPI(可选)
在 Apifox / Swagger UI / Postman 中选择 Import → OpenAPI 3.1 → 上传
openapi-v1.json;文档包含请求体 schema、响应包络、错误码清单与回调事件标注。
参数表
签名请求头
| 请求头 | 示例 | 规则 |
|---|---|---|
App-Key | demo | 应用 AppKey;不存在返回 1017 |
Nonce | 9f2a7c1b | 8-64 字符;同一 AppKey 下 5 分钟内不可重复,重复返回 1020 |
Timestamp | 1750000000000 | epoch 毫秒;与服务器时间偏差超过 300000ms 返回 1019 |
Signature | 372e885320aabd997aafc5491f9d90fdca94432e | hex(sha1(AppSecret + Nonce + Timestamp)),小写;不匹配返回 1018 |
集合 / 环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
host | http://127.0.0.1:8080 | 服务端基地址,不含 /im/v2 |
appKey | demo | 应用 AppKey |
appSecret | YOUR_APP_SECRET | 应用 AppSecret(仅服务端持有) |
nonce / timestamp / signature | 空 | 由前置脚本每次请求写入,不要手工填 |
导出范围
| 项 | 值 |
|---|---|
| Open API 操作数 | 230 |
| 能力分组 | 20 个(用户、好友关系链、黑名单、消息、群组、超级群、聊天室、会话、在线状态、敏感词、回调配置与投递、服务开通、运营统计、AI 助理代理、机器人、推送通道、sensitiveword、statusmessage、entrust、ultragroup) |
| 响应包络 | {code,msg?,data?,requestId?} |
| 错误码来源 | 契约错误码表(每个 operation 的 errors 写入 x-idl-errors) |
| 签名字段来源 | 契约中的 auth.signatureAlgorithm 声明 |
示例
签名与调用(Node.js)
// openapi-call.mjs — 计算签名并调用一个 Open API(Node.js 18+,使用内置 fetch)
// 运行前变量:APP_KEY / APP_SECRET(控制台创建应用后获得)、IM_HOST(默认本地)。
import { createHash, randomBytes } from 'node:crypto';
const HOST = process.env.IM_HOST || 'http://127.0.0.1:8080';
const APP_KEY = process.env.APP_KEY || 'demo'; // 变量:AppKey
const APP_SECRET = process.env.APP_SECRET || 'YOUR_APP_SECRET'; // 变量:AppSecret
function sign(secret, nonce, timestamp) {
return createHash('sha1').update(secret + nonce + timestamp).digest('hex');
}
async function call(path, body) {
const nonce = randomBytes(8).toString('hex'); // 8-64 字符,5 分钟内不可重复
const timestamp = String(Date.now()); // epoch 毫秒,±300000ms
const signature = sign(APP_SECRET, nonce, timestamp);
const res = await fetch(HOST + '/im/v2' + path, {
method: 'POST',
headers: {
'content-type': 'application/json',
'App-Key': APP_KEY,
Nonce: nonce,
Timestamp: timestamp,
Signature: signature,
},
body: JSON.stringify(body),
});
const json = await res.json();
console.log(res.status, JSON.stringify(json));
return json;
}
// 1) 注册用户(幂等:已存在则更新资料)
await call('/user/register', { userId: 'alice', name: 'Alice' });
// 2) 查询用户
await call('/user/get', { userId: 'alice' });Postman 环境 JSON
{
"name": "NI PaaS IM Local",
"values": [
{
"key": "host",
"value": "http://127.0.0.1:8080",
"enabled": true
},
{
"key": "appKey",
"value": "demo",
"enabled": true
},
{
"key": "appSecret",
"value": "YOUR_APP_SECRET",
"enabled": true
}
],
"_postman_variable_scope": "environment"
}集合前置脚本(Postman 内已内置)
// 由 generate.mjs 生成的集合级前置脚本:自动计算 App-Key 签名。
// Signature = hex(sha1(AppSecret + Nonce + Timestamp)),与服务端实现一致。
const CryptoJS = require('crypto-js');
const appSecret = pm.collectionVariables.get('appSecret') || '';
const nonce = CryptoJS.lib.WordArray.random(8).toString(); // 16 位 hex,满足 8-64 字符
const timestamp = String(Date.now());
pm.collectionVariables.set('nonce', nonce);
pm.collectionVariables.set('timestamp', timestamp);
pm.collectionVariables.set('signature', CryptoJS.SHA1(appSecret + nonce + timestamp).toString());命令行校验导出物
# 下载导出物后校验操作数与分组
curl -sS -o openapi-v1.json http://127.0.0.1:8080/docs/assets/openapi-v1.json
node -e "const o=require('./openapi-v1.json');console.log(o['x-idl-operation-count'], Object.keys(o.paths).length, o.tags.length)"
curl -sS -o postman-collection.json http://127.0.0.1:8080/docs/assets/postman-collection.json
node -e "const c=require('./postman-collection.json');console.log(c.info.schema, c.item.length, c.item.reduce((n,f)=>n+f.item.length,0))"常见问题
401 且 code=1018
签名不匹配。检查是否用了「AppSecret + Nonce + Timestamp」的顺序、是否小写 hex、Nonce/Timestamp 是否与参与计算的值一致(Postman 中确认集合变量已写入)。
401 且 code=1019
Timestamp 超出 ±300000ms。确认使用毫秒时间戳(13 位),并校准本机时间。
401/403 且 code=1020
Nonce 被重放。每次请求都要新的 Nonce;重发同一个 Postman 请求时会自动重新执行前置脚本,不会复用。
403 且 code=1017
AppKey 不存在或应用已停用(disabled)。用 Admin API 确认应用状态。
403 且 code=1021
对应服务未开通(service.activation)。到控制台「服务开通」或 POST /api/admin/apps/{appkey}/services 打开。
为什么全部接口都是 POST?
Open API 统一使用 POST + JSON body(含查询类接口),签名头对方法无感;这是契约约定,不是文档笔误。
Postman 里 CryptoJS 报错
使用 Postman v10+;脚本通过 require('crypto-js') 加载内置模块。企业离线版如禁用该模块,请改用 Node 脚本调试。
OpenAPI 导入后"服务器地址"不对
servers[0] 是本地默认地址;导入后把 server 改成自己的域名(保留 /im/v2 前缀)。
相关链接
- 鉴权与签名:签名算法、时间窗与 Nonce 规则的完整说明
- API 接口列表:按模块浏览全部接口
- 状态码与错误码:1018/1019/1020/1021 等处理方式
- 限频、配额与容量限制:429 与 Retry-After
- 服务端回调:接口触发的回调事件
- 功能与套餐开通对照表:服务开通项与接口的对应关系