| 凭证 | 长度 | 用途 |
|---|---|---|
key | 32 位 | 应用实例标识,随每次请求明文传递 |
secret | 64 位 | 签名密钥,只参与签名计算,不随请求传递 |
aesKey | 32 位 | 业务参数加密密钥,同样不随请求传递 |
| 环境 | 网关地址 |
|---|---|
| 测试环境 | https://scthub-open.dev.dmqwl.com |
| 生产环境 | 上线时提供 |
POST,请求头 Content-Type: application/json,请求体固定为 4 个字段:| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
key | string | 是 | 应用实例的 key |
timestamp | number | 是 | 发起请求时的毫秒时间戳,如 1794370000000 |
body | string | 是 | 业务参数 JSON 字符串加密后的 Base64 密文,见第 3 节 |
sign | string | 是 | 签名,见第 4 节 |
{
"key": "调用方的key",
"timestamp": 1794370000000,
"body": "43EYRVvX8lxqL6rR/XZ+iBSNgsos0HHX8JUVQJsDDhk=",
"sign": "6D1F10D8A10FB9580628DA5C4C00E1CD"
}{} 加密。corpCode 字段,它会让网关改走另一套(服务商)验签规则。body:| 项 | 取值 |
|---|---|
| 算法 / 模式 / 填充 | AES/CBC/PKCS5Padding(等同 PKCS7) |
| 密钥 | aesKey 字符串的 UTF-8 字节,共 32 字节,即 AES-256。直接取字节,不做 Hex 或 Base64 解码 |
| IV | 密钥的前 16 个字节,即 aesKey 的前 16 个字符 |
| 明文 | 业务参数 JSON 字符串,UTF-8 编码 |
| 输出 | 标准 Base64(含 + / =,不换行,非 URL-safe) |
sign = MD5( body + timestamp + secret )body:第 3 节得到的 Base64 密文字符串。签名针对密文而不是明文,所以必须先加密、后签名。timestamp:与请求体中 timestamp 完全一致的十进制数字串。secret:签名密钥原文。| 顺序 | 校验内容 | 不通过时返回 |
|---|---|---|
| 1 | Content-Type 是否为 application/json | 405 无效的请求内容 |
| 2 | key 是否存在 | 1037 无效的key |
| 3 | key 是否启用 | 1031 用户状态有误,请联系管理员 |
| 4 | 用该 key 的 secret 按第 4 节重算签名,与 sign 比较(忽略大小写) | 1037 数据验证失败 |
| 5 | 请求地址是否为已登记的接口 | 405 无效的请求信息 |
| 6 | 该应用实例是否已被授权此接口 | 405 用户权限不足 |
| 7 | 实例开启了 IP 白名单时,来源 IP 是否在白名单内 | 1044 请求的ip不在白名 单当中 |
| 8 | 用 aesKey 解密 body | 1020 无效的AES数据格式 |
timestamp 只参与签名,服务端不校验时效,也没有防重放机制。 同一个已签名的请求可以被重复提交。请妥善保管 secret,只通过 HTTPS 调用,并建议向平台申请开启 IP 白名单。退单类接口自身不会重复退款,详见对应接口文档。X-Forwarded-For 的第一个地址。200。响应体有两种形态,先判断再处理:| 形态 | 判断方法 | 处理方式 |
|---|---|---|
| 密文 | 响应体不以 { 开头 | 请求已通过网关校验。用 aesKey 按第 3 节的算法解密,得到统一响应 JSON |
| 明文 JSON | 响应体以 { 开头 | 请求被网关拒绝(第 5 节任一步未通过)或系统异常。不要解密,直接读取 code 和 message |
| 字段 | 类型 | 说明 |
|---|---|---|
code | number | 0 表示成功,其他值表示失败 |
msg | string | 失败原因;成功时为 null |
data | object / array | 业务数据,结构见各接口的「响应业务字段」;失败时为 null |
ok | boolean | 是否成功,等价于 code == 0 |
{"code": 0, "msg": null, "data": {}, "ok": true}{"code": 405, "msg": "订单不存在", "data": null, "ok": false}message(不是 msg):{"code": 1037, "data": null, "message": "数据验证失败"}"payAmount": "20000");数量为数字。yyyy-MM-dd HH:mm:ss,日期格式 yyyy-MM-dd。null。body 和 sign 应与表中完全一致。| 项 | 值 |
|---|---|
| aesKey | 0123456789abcdef0123456789abcdef |
| secret | demo_secret_do_not_use_0000000000000000000000000000000000000000 |
| timestamp | 1794370000000 |
| 业务参数(明文) | {"orderNo":"SO202611110001"} |
aesKey 的 32 个字节,IV 为 0123456789abcdef 这 16 个字节:body = 43EYRVvX8lxqL6rR/XZ+iBSNgsos0HHX8JUVQJsDDhk=43EYRVvX8lxqL6rR/XZ+iBSNgsos0HHX8JUVQJsDDhk=1794370000000demo_secret_do_not_use_0000000000000000000000000000000000000000sign = 6D1F10D8A10FB9580628DA5C4C00E1CD{ 开头时用同一个 aesKey 解密,得到统一响应 JSON。-K 是 aesKey 的十六进制,-iv 是其前 16 字节的十六进制):pip install pycryptodome requests)message)| code | message | 原因与处理 |
|---|---|---|
1037 | 无效的key | key 不存在。检查 key 是否填错、是否用错环境 |
1037 | 数据验证失败 | 签名不匹配,或缺少 sign。按第 10 节排查 |
1031 | 用户状态有误,请联系管理员 | key 已被禁用,联系平台管理员 |
1044 | 请求的ip不在白名单当中 | 来源 IP 未加入该实例的白名单 |
1020 | 无效的AES数据格式 | body 不是用该实例 aesKey 加密的合法密文 |
405 | 无效的请求内容 | Content-Type 不是 application/json |
405 | 无效的请求信息 | 请求地址不是已登记的接口,检查路径拼写 |
405 | 用户权限不足 | 该实例未被授权此接口,联系平台管理员授权 |
400 | Bad Request | 业务服务异常,可稍后重试;持续出现请联系平台 |
500 | common.system.busy | 请求体不是合法 JSON,或网关内部异常 |
msg)| code | 说明 |
|---|---|
0 | 成功 |
405 | 业务校验不通过,msg 为具体原因,各接口文档列出了常见提示 |
1037 数据验证失败 时,按顺序检查:body 与参与签名的 body 是否是同一个字符串。常见问题是加密了两次得到两个不同的密文,或 HTTP 库对 + / = 做了转义。timestamp 与参与签名的时间戳是否一致,是否被序列化成了科学计数法或带小数。secret 是否与 key 属于同一个应用实例、同一个环境,前后是否混入了空格或换行。body + timestamp + secret,中间是否多了分隔符。body 和 sign 都一致才说明算法正确。1020 无效的AES数据格式 时,检查密钥是否直接取 aesKey 的 UTF-8 字节(不要做 Hex 解码)、IV 是否为密钥前 16 字节、模式是否为 CBC、输出是否为标准 Base64。