开发
API

附录

回调签名算法

小程序平台所有发往开发者服务端请求。都会使用如下的算法进行签名,用来验证请求的来源:

  1. 将所有字段(验证时注意不包含 msg_signature 签名本身,不包含空字段与 type 常量字段)内容与平台上配置的 token 一起,按照字典序排序
  2. 所有字段内容连接成一个字符串
  3. 使用 sha-1 算法计算字符串摘要作为签名。

golang 示例

 var sortedString []string
 sortedString = append(sortedString, token)
 sortedString = append(sortedString, timestamp)
 sortedString = append(sortedString, nonce)
 sortedString = append(sortedString, msg)
 sort.Strings(sortedString)
 h := sha1.New()
 h.Write([]byte(strings.Join(sortedString, "")))
 bs := h.Sum(nil)
 _signature := fmt.Sprintf("%x", bs)

nodejs 示例(Koa)

// http handler GET
 // function handler(ctx) {
   const { signature, timestamp, msg: '', nonce, echostr } = ctx.query;
   const strArr = [token, timestamp, nonce, msg].sort();
   const str = strArr.join('');
   const _signature = require('crypto').createHash('sha1').update(str).digest('hex');

回调响应

在开发者服务端收到回调且处理成功后,需要按以下 json 返回表示处理成功,否则会认为通知失败进行重试。

{
  "err_no": 0,
  "err_tips": "success"
}

对于未收到成功返回的通知,消息最大重试次数为 16 次,重试次数和延迟关系如下:

重复次数延迟时间
110s
230s
31m
42m
53m
64m
75m
86m
97m
108m
119m
1210m
1320m
1430m
151h
162h

请求签名算法

发往小程序服务端的请求,在没有特殊说明时,均需要使用担保支付秘钥进行签名,由于保证请求的来源:

1. sign, app_id , thirdparty_id 字段用于标识身份字段,不参与签名。将其他字段内容(不包含 key)与支付 SALT 一起进行字典序排序后,使用&符号链接 2. 使用 md5 算法对该字符串计算摘要,作为结果 3. 参与加签的字段均以 POST 请求中的 body 内容为准, 不考虑参数默认值等规则. 对于对象类型与数组类型的参数, 使用 POST 中的字符串原串进行左右去除 空格后进行加签 4. 如有其他安全性需要, 可以在请求中添加 nonce 字段, 该字段无任何业务影响, 仅影响加签内容, 使统一请求的多次签名不同 5. 空字符串与省略参数不参与加签

以如下的分账请求典型值为例:

{
  "settle_params": "[{\"merchant_uid\":\"123345\",\"amount\":1}]",
  "thirdparty_id": "ttc72cb19158066a6b",
  "settle_desc": "开始结算与分账",
  "out_settle_no": "mock_settle_no",
  "out_order_no": "mock_settle_no",
  "notify_url": "https://callback.com",
  "app_id": "ttabcdefg123456",
  "sign": "3c9421d0268a974138f4b36e9cefa1f1"
}

假设支付秘钥值为 your_payment_salt,经过剔除参数排序,得到 MD5 前的字符串为

[{"merchant_uid":"123345","amount":1}]&https://callback.com&mock_settle_no&mock_settle_no&your_payment_salt&开始结算与分账

MD5 计算后得到最终签名 3c9421d0268a974138f4b36e9cefa1f1

golang 示例加签

    var sortedString []string
    sortedString = append(sortedString, salt)
    sortedString = append(sortedString, param1)
    sortedString = append(sortedString, param2)
    sortedString = append(sortedString, param3)
    sort.Strings(sortedString)
    h := md5.New()
    h.Write([]byte(strings.Join(sortedString, "&")))
    return fmt.Sprintf("%x", h.Sum([]byte(toSignStr)))

js 示例加签

// params 代表请求内容
var skip_arr = ["thirdparty_id", "app_id", "sign"];
var paramArray = new Array();
for (var k in params) {
  if (skip_arr.indexOf(k) != -1) {
    continue;
  }
  paramArray.push(params[k]);
}
paramArray.push(SALT);
paramArray.sort();
var signStr = paramArray.join("&");
return md5(signStr);

PHP 示例加签

    /**
     * 计算签名
     */
    protected function getSign($params)
    {
        unset($params["sign"]);
        unset($params["app_id"]);
        unset($params["thirdparty_id"]);
        $paramArray = [];
        foreach ($params as $param) {
            $paramArray[] = trim($param);
        }
        $paramArray[] = trim($this->paysecret);
        sort($paramArray,2);
        $signStr = trim(implode('&', $paramArray));
        return md5($signStr);
    }

手续费计算规则

手续费=floor((订单总金额-已退款金额)*0.006)

手续费计算需要根据当前用户可操作金额(订单总金额-已退款或结算金额)计算,对乘费率千分之六后的金额向下取整即为该笔交易的手续费。

手续费会在调用结算时扣减,若该笔交易在结算后产生退款等行为,手续费不会回退。

错误码与常见问题

如何获得支付秘钥

  1. 注意,小程序支付秘钥 SALT 不同于 app secret 等秘钥,为保障安全性,担保支付系统分配生成的
  2. 无法按文档说明获取 SALT 时,请检查进件状态。只有在进件完成后,秘钥才会展示

请求返回错误码 1005:

  1. 请对照文档检查字段类型,例如,系统中所有的标识金额的字段为以分为单位的整型数。该错误码大多由整型数与字符串类型混淆导致。

请求返回 2008 签名错误:

  1. 计算签名可以参考以上 Demo 进行,由于不同的语言特性不一致,请参考描述自行根据实际情况处理。
  2. 请确认使用了正确的秘钥进行加签。请求加签需要使用担保支付秘钥 SALT,使用 callbackToken 与 app secret 等都会导致加签失败
  3. 加签不需要针对字段去重,使用 Java 中的 TreeMap 等数据结构可能会在字段重复时报错
  4. 请检查最终请求 Body 中的字段是否包含转义字符,一些语言工具的序列化会加入转义字符,导致验签失败
点击纠错
评价此篇文档