OpenAPI 与 Postman 调试

本页给出由 IDL 自动导出的 OpenAPI 3.1 描述与 Postman v2.1 集合:两者都包含全部 230 个 Open API 操作、统一响应包络与签名头,随文档构建重新生成。第一次调试建议先跑通本页的 Node 脚本,再导入 Postman 批量试接口。

概念​

导出物路径格式用途
OpenAPI 描述docs-site/assets/openapi-v1.jsonOpenAPI 3.1.0导入 Apifox / Swagger UI / Postman / 代码生成器
Postman 集合docs-site/assets/postman-collection.jsonPostman 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/ 下存在两个导出文件。

步骤​

  1. 获取导出物

    从本页上方链接下载 openapi-v1.json 与 postman-collection.json;它们随每次发布自动刷新,与当前契约一致。

  2. 直接用 Node 调通一个接口

    运行下方「签名与调用」脚本;先 user.register 再 user.get,两次都应返回 code=0。

  3. 导入 Postman 集合

    Postman → Import → 选择 postman-collection.json;左侧出现「NI PaaS IM Open API」集合,按能力分为用户/消息/群组等文件夹。

    集合级 Pre-request Script 会自动写入 nonce、timestamp、signature 三个集合变量,无需手工计算。

  4. 设置集合同变量

    在集合的 Variables 页把 host、appKey、appSecret 改为自己的值;host 不带 /im/v2(请求路径会自动拼接)。

    也可以新建环境并导入下方环境 JSON,效果相同。

  5. 发送请求

    选「用户 → 注册用户」,Body 已是脚本生成的示例 JSON,点击 Send。

    返回 {"code":0,"data":{...},"requestId":"..."} 即成功;401/403 见下方常见问题。

  6. 导入 OpenAPI(可选)

    在 Apifox / Swagger UI / Postman 中选择 Import → OpenAPI 3.1 → 上传 openapi-v1.json;文档包含请求体 schema、响应包络、错误码清单与回调事件标注。

参数表​

签名请求头​

请求头示例规则
App-Keydemo应用 AppKey;不存在返回 1017
Nonce9f2a7c1b8-64 字符;同一 AppKey 下 5 分钟内不可重复,重复返回 1020
Timestamp1750000000000epoch 毫秒;与服务器时间偏差超过 300000ms 返回 1019
Signature372e885320aabd997aafc5491f9d90fdca94432ehex(sha1(AppSecret + Nonce + Timestamp)),小写;不匹配返回 1018

集合 / 环境变量​

变量默认值说明
hosthttp://127.0.0.1:8080服务端基地址,不含 /im/v2
appKeydemo应用 AppKey
appSecretYOUR_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
// 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​

ni-paas-im-local.postman_environment.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 内已内置)​

Pre-request Script
// 由 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());

命令行校验导出物​

Shell
# 下载导出物后校验操作数与分组
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 前缀)。

相关链接​