看店通提供多语言服务端 SDK(Java、PHP、Node.js、Python,以项目交付包为准),把令牌缓存、签名计算、重试退避、错误映射这些重复劳动封装掉,让你只关心业务调用。本文讲 SDK 的安装、初始化与调用方式;协议层面的认证规则请以API 鉴权说明为准,本文不重复定义。
一、获取与安装
标准交付通过私有 Git 仓库或压缩包提供,SDK 的主版本号与 OpenAPI 主版本号对齐(SDK 1.x 对应
/v1)。安装包附带 SHA-256 校验文件,请在安装前比对,不一致不要使用。请勿从搜索引擎找到的第三方镜像下载,历史上出现过被植入后门的仿冒包。
依赖环境要求:Java 8 及以上、PHP 7.4 及以上、Node.js 16 及以上、Python 3.8 及以上。SDK 只依赖各语言的标准 HTTP 客户端与 JSON 库,不引入重型框架,可以安全地放进已有工程。
二、初始化与配置
凭证通过环境变量注入,不要硬编码在代码里,也不要提交到版本库:
# 环境变量
KDT_APP_ID=kdt_app_10086
KDT_APP_SECRET=your_app_secret
KDT_BASE_URL=https://api.kandiantong.com/v1
// Node.js
const { KdtClient } = require('@kandiantong/sdk');
const client = new KdtClient({
appId: process.env.KDT_APP_ID,
appSecret: process.env.KDT_APP_SECRET,
baseUrl: process.env.KDT_BASE_URL,
timeoutMs: 5000,
maxRetries: 3
});
其他语言的 API 形态一致,都是 CredentialProvider、HttpClient、Service
三层:凭证层负责令牌的获取与缓存,传输层负责超时、重试与签名,服务层按接口域划分(client.order、client.product、client.inventory)。
三、发起调用
try {
const order = await client.order.get({ order_no: 'KDT202609290001' });
console.log(order.status, order.pay_amount_fen);
} catch (err) {
if (err instanceof KdtApiError) {
// err.code 为业务码,err.requestId 用于提工单
if (err.code === 40401) {
// 订单不存在,按业务逻辑跳过
} else {
throw err;
}
} else {
throw err; // 网络类异常,交由上层重试
}
}
请求参数与返回字段都保持服务端的 snake_case 命名,SDK 不做驼峰转换,这样你在文档、抓包、日志三处看到的字段名完全一致,排查问题时不需要做心算映射。订单号字段统一是
order_no。
四、内置能力
- 令牌自动管理:首次调用时获取 access_token 并缓存,剩余有效期不足 300 秒时自动刷新。多实例部署请配置共享缓存(见下节),否则每个实例各自刷新会浪费配额。
- 签名自动计算:对需要签名的敏感接口自动生成
X-Kdt-Timestamp、X-Kdt-Nonce、X-Kdt-Signature,并保证对 raw body 签名,不会被序列化差异坑到。 - 重试与退避:对 HTTP 429 读取
Retry-After后等待重试,对 5xx 做指数退避,对 4xx 不重试。写接口重试时自动复用同一个Idempotency-Key,不会产生重复单。 - 分页迭代器:
for await (const order of client.order.iterate({...}))自动翻页,不用手写page循环,也不会因为忘记判断total而死循环。 - 日志脱敏:默认对手机号中间四位、收货地址、身份证号做掩码,AppSecret 与 access_token 永不出现在日志中。
- Webhook 验签工具:提供
verifyWebhook(rawBody, headers, secret)辅助函数,内部使用定长比较,规则见事件回调 Webhook。
五、多实例与并发
单机部署时 SDK 默认把令牌放在进程内存里,够用。一旦横向扩容到多实例,就要把令牌缓存换成 Redis,并在刷新时加分布式锁,否则实例数越多、令牌接口的调用量越大,很容易撞上限流。配置方式是在初始化时传入自定义的 tokenStore 实现(需要提供 get 和 set 两个方法)。
并发控制方面,SDK 内置了按 AppId 维度的客户端限速器,默认读接口 600 次/分钟、写接口 120 次/分钟,与服务端配额一致。这是本地预防性限速,不能替代对 429 的处理;如果你自己起了多个进程,记得把限速阈值按实例数等分,否则各自都以为没超。
六、测试与联调
用沙箱环境的 AppId 与 AppSecret 跑集成测试,配合固定的 fixture 订单号,让测试结果可复现。CI 流水线中只能使用沙箱凭证,生产密钥不得进入任何构建环境;如果 CI 平台支持,请把凭证标记为受保护变量并开启日志掩码。
离线测试可以启动 SDK 附带的 mock 服务器,它会按 OpenAPI 定义返回样例响应,适合在没有网络的环境里跑单元测试。需要验证异常分支时,mock 服务器支持强制返回指定的 HTTP 状态码与业务码,可以方便地构造 429 和 5xx 场景,确认你的重试逻辑真的生效。
七、常见问题
| 现象 | 常见原因 | 处理办法 |
|---|---|---|
| 业务码 40001 签名失败 | 请求体被日志或字段裁剪中间件改写 | 确保对 raw body 签名,把 SDK 的拦截器放在所有改写型中间件之后 |
| 业务码 40003 时间戳超窗 | 容器未同步宿主机时钟 | 为容器配置 NTP,或挂载宿主机的时间同步 |
| 频繁收到 401 | 多实例各自缓存令牌且互相挤兑 | 改用共享 tokenStore 并加分布式锁 |
| TLS 握手失败 | 企业出口代理做了 HTTPS 解密 | 把代理根证书加入信任库,或在初始化时配置 proxy 参数 |
| 中文乱码 | 运行环境默认编码不是 UTF-8 | 显式设置 JVM 的 file.encoding 或 PHP 的 default_charset 为 UTF-8 |
| 批量任务持续 429 | 固定间隔重试,窗口始终无法恢复 | 改为指数退避,并把任务挪到夜间窗口匀速消费 |
八、典型场景:与 ERP 对接
最常见的批处理链路是:用分页迭代器拉取待发货订单,逐单写入 ERP,ERP 出库后调用发货回写接口。这个链路要注意两件事:一是拉取时以 updated_at 为增量游标,用
created_at 会漏掉历史单的状态变更;二是回写发货接口要带 Idempotency-Key,值用订单号加运单号的组合,这样即使 ERP 侧重复触发也不会重复发货。
库存同步不建议做成定时全量覆盖,那会在大促时把可售库存刷回旧值造成超卖。正确做法是事件驱动增量更新,再用每日夜间的全量校准任务兜底,差异超过阈值时告警而不是静默覆盖。完整的字段映射表与对账口径见ERP 对接指南;协议层细节见OpenAPI 总览;服务端加固要求见安全规范。