接口回调
接口回调是指:您主动调用平台的某个开放接口(如 org.save 新增组织),平台在业务处理完成后,将结果异步推送回您的系统。
与事件回调的区别:
| 维度 | 接口回调(本文档) | 事件回调 |
|---|---|---|
| 触发者 | 您调用的某个接口(一对一) | 平台主数据变动(一对多,订阅即推送) |
| 消息 type | CALLBACK | EVENT_PUSH |
| 标识字段 | method = 接口名,callLogId = 调用日志 ID | method = 事件编码,eventTriggerId = 触发记录 ID |
| 回调地址 | 调用接口时通过 notifyUrl 参数指定(未指定则用平台配置的地址) | 平台应用密钥中配置的 notifyUrl |
通常情况下,只有在接口超过 5s 才能返回时,才需要异步回调——同步接口直接等待返回即可,无需使用本链路。
1. 链路概述
推送失败后由平台定时重试(梯度间隔),详见第 7 节重试机制。
2. 接入前准备
在开放平台控制台的应用密钥配置中,确认以下参数(详见准备工作):
| 参数名 | 说明 |
|---|---|
| 通知地址(notifyUrl) | 默认回调地址。调用接口未传 notifyUrl 参数时使用 |
| 事件订阅状态(notifyState) | 通知开关 |
| 加密类型(notifyEncryptionType) | 加密模式:0-明文模式、1-兼容模式、2-安全模式(推荐) |
| 签名校验令牌(notifyToken) | 生成和验证 signature / msgSignature |
| 消息加解密秘钥(notifyEncodingAesKey) | AES 加解密密钥,43 字符(用于消息体加解密) |
3. 触发回调
并非所有接口都会回调,是否回调取决于接口的业务实现(例如 org.save 新增组织后会回调)。
调用接口时在公共参数中传入 notifyUrl,或在平台为应用配置默认回调地址。使用 SDK 时,通过请求对象设置(参考 OpenConfig.notifyUrl 参数名)。
4. 回调消息格式
4.1 URL 参数
平台以 HTTP POST 请求您的回调地址,URL 上追加以下参数(小写驼峰):
| 参数 | 说明 |
|---|---|
| signature | 签名:SHA1(sort(token, timestamp, nonce, "")),所有模式都携带 |
| msgSignature | 消息签名:SHA1(sort(token, timestamp, nonce, encrypt)),仅加密模式(兼容/安全)携带 |
| timestamp | 秒级时间戳 |
| nonce | 16 位随机字符串 |
| encryptType | 加密类型,加密模式下为 aes(明文模式不传) |
4.2 请求体(明文部分)
明文业务 JSON 结构如下(bizContent 为业务参数):
{
"type": "CALLBACK",
"method": "org.save",
"appKey": "您的appKey",
"version": "1.0",
"timestamp": "1754280000",
"callLogId": 1234567890,
"bizContent": { "id": 10001 }
}三种加密模式下实际发送的请求体:
| 模式 | 请求体 |
|---|---|
| 0-明文模式 | 明文 JSON 本身(无 encrypt 字段,URL 无 encryptType/msgSignature) |
| 1-兼容模式 | 明文字段展开 + encrypt(密文)+ appKey |
| 2-安全模式 | 仅 encrypt(密文)+ appKey |
5. 消息加解密详解
与事件回调完全一致,此处仅列要点,详见事件回调-加解密:
AESKey=Base64Decode(encodingAesKey + "="),32 字节;AES-256-CBC,IV 取 AESKey 前 16 字节,PKCS7 填充;- 平台加密明文串结构:
random(16字节) + msgLen(4字节网络字节序) + msg(明文JSON) + appKey; - 解密后校验尾部 appKey 与您的一致(防串扰);
- 验签:
signature = SHA1(sort(token, timestamp, nonce, "")),加密模式下校验msgSignature = SHA1(sort(token, timestamp, nonce, encrypt))。
6. 回调接收端实现
平台 SDK(mdp-sdk-core 的 top.mddata.sdk.core.aes.MdpBizMsgCrypt)已封装以上全部逻辑,接收端实现示例:
@PostMapping("/notify/callback")
public ApiResponse callback(HttpServletRequest request, @RequestBody String content) {
// 1. 从URL获取验签参数
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String msgSignature = request.getParameter("msgSignature");
String encryptType = request.getParameter("encryptType");
// 2. 从请求体提取 appKey(明文/兼容模式在body中;安全模式body里也有appKey字段)
JSONObject body = JSON.parseObject(content);
String appKey = body.getString("appKey");
// 3. 用本地配置的 token / encodingAesKey 构建加解密实例
MdpBizMsgCrypt crypt = new MdpBizMsgCrypt(token, encodingAesKey, appKey);
// 4. 验签 + 解密
String plaintext;
if (StrUtil.isBlank(encryptType)) {
// 明文模式:验 signature,消息体即明文
boolean verified = crypt.verifySignature(timestamp, nonce, "", signature);
if (!verified) { return ApiResponse.error("验签失败"); }
plaintext = body.toJSONString();
} else {
// 加密模式(兼容/安全):decryptMsg 内部完成 msgSignature 验签 + AES 解密
plaintext = crypt.decryptMsg(body.getString("encrypt"), timestamp, nonce, msgSignature);
}
// 5. 按type分发:CALLBACK 为接口回调,EVENT_PUSH 为事件推送
JSONObject bizData = JSON.parseObject(plaintext);
if ("CALLBACK".equals(bizData.getString("type"))) {
String method = bizData.getString("method"); // 接口名,如 org.save
Long callLogId = bizData.getLong("callLogId"); // 对应的调用日志ID
Object bizContent = bizData.get("bizContent"); // 业务数据
// ... 根据 method 分发到具体业务处理器
}
// 6. 处理成功必须返回 code=0,否则平台会判定失败并重试
return ApiResponse.success("");
}判定成功的唯一标准:您的接收端返回 HTTP 200 且响应体 JSON 中
code=0(即{"code": 0, "msg": ""})。返回其他任何格式或非 0 值都会触发重试。
7. 重试机制
- 回调失败(网络异常、超时、返回值非
code=0、响应无法解析为{"code":0})后,平台按梯度间隔重试; - 默认重试策略:最多 5 次,间隔
2分钟 → 5分钟 → 30分钟 → 6小时 → 12小时; - 重试次数用尽后任务置为"重试结束"状态,可在管理端手动重推或手动结束;
- 每次推送(含失败)均有日志记录(含请求体、响应体、错误原因),可在管理端查询。
8. 常见问题
Q1:回调一直失败重试?
检查接收端是否严格返回 {"code": 0, "msg": ""};平台解析不了响应体会记录"返回值格式错误,无法解析为 ApiResponse.class"。
Q2:验签失败?
确认您本地保存的 notifyToken 与平台配置一致;signature 计算时 encrypt 参数在明文模式下为空字符串。
Q3:解密失败或 appKey 校验不通过?
encodingAesKey必须为 43 字符(平台生成规则:32 字节随机数 Base64 后去掉末尾=);- 解密后尾部的 appKey 与您的 appKey 必须一致,确认您用对了应用的密钥。
Q4:没有收到回调?
- 确认平台应用密钥中
notifyState(通知开关)已开启; - 确认调用接口时传了
notifyUrl或平台已配置默认回调地址; - 确认该接口的业务实现中确实发起了回调(并非所有接口都会回调);
- 在管理端回调任务列表查看任务状态,以及每次推送的请求体、响应体、错误原因日志。