最近有朋友需要在微信小程序内使用招商银行一网通支付,目前能支持的支付类型只有H5支付接口,所以记录下整个调试流程和调试过程可能出现的问题,写测试报告时需要注意的事项也记录下,以备以后需要时,可以及时找出,免踩坑。
**微信小程序下H5支付,用户操作流程,小程序(小程序原生)内通过点击—》访问到提交订单页面(webview包含的订单外链页)-》跳转到一网通H5支付页面——》支付成功回到支付成功页面(webview包含的订单外链页)——》点击支付完成回到小程序页面(小程序原生)**
一网通H5操作流程图
**以下流程采用PHP进行调试和测试**
先定义一个总配置数组
$config = [ 'use_sandbox' => true, // 是否使用 招商测试系统 'branch_no' => 'xxxx', // 商户分行号,4位数字 'mch_id' => 'xxxx', // 商户号,6位数字 'mer_key' => '1234567890123456', // 秘钥16位,包含大小写字母 数字 // 招商的公钥,建议每天凌晨2:15发起查询招行公钥请求更新公钥。 'cmb_pub_key' => 'xxxx', 'op_pwd' => 'xxxxxx', // 操作员登录密码。 'sign_type' => 'SHA-256', // 签名算法,固定为“SHA-256” 'limit_pay' => 'A', // 允许支付的卡类型,默认对支付卡种不做限制,储蓄卡和信用卡均可支付 A:储蓄卡支付,即禁止信用卡支付 'notify_url' => 'http://cmb.admin.com/cmb_tz.php', // 支付成功的回调 'sign_notify_url' => 'http://cmb.admin.com/cmb_tz.php', // 成功签约结果通知地址 'sign_return_url' => 'http://cmb.admin.com', // 成功签约结果通知地址 'return_url' => 'http://cmb.admin.com/cmb_ok.php', // 如果是h5支付,可以设置该值,返回到指定页面 ];
一网通支付时需要一个sign签名字段,签名内容是reqData内容,定义一个签名函数
//签名 function make_sign($mer_key,$str){ $reqData = arraySort($str); $signStr = createLinkString($reqData); $signStr .= '&'.$mer_key; //SHA-256签名 $baSrc = mb_convert_encoding($signStr,"UTF-8"); $baResult = hash('sha256', $baSrc); //转为16进制字符串(可选) //$sign = bin2hex($baResult); return $baResult; }
1.一网通支付中H5类型,可能用到的接口有3个,获取公钥接口、一网通下单接口、查询订单接口
//一网通获取公钥地址(测试) $QueryKeyAPI_test = 'http://mobiletest.cmburl.cn/CmbBank_B2B/UI/NetPay/DoBusiness.ashx'; //一网通下单地址(测试) $OneCardPayAPI_test = 'http://121.15.180.66:801/netpayment/BaseHttp.dll?MB_EUserPay'; //$OneCardPayAPI_test ='http://paytest.cmburl.cn:801/netpayment/BaseHttp.dll?MB_EUserPay'; //查询订单 $DoBusiness_test = 'http://121.15.180.66:801/netpayment_directlink_nosession/BaseHttp.dll?QuerySingleOrder';
2.获取公钥目的套用一网通自己的话:使用招行公钥验签(用于对“成功签约结果通知”和“成功支付结果通知”接收到的通知报文进行验签)
(1)公钥获取的数组
$pub_get_data = [ 'version' => '1.0', 'charset' => 'UTF-8', 'signType' => $config['sign_type'], 'reqData' => [ 'dateTime' => date('YmdHis', $nowTime), 'txCode' => 'FBPK', 'branchNo' => $config['branch_no'], 'merchantNo' => $config['mch_id'], ], ];
公钥获取方式可以直接采用CURL方式获取。
对reData内容进行签名,Json后然后放入jsonRequestData字段:
$baResult = make_sign($config['mer_key'],$pub_get_data['reqData']); $pub_get_data['sign']=$baResult; $formParams['jsonRequestData']=json_encode($pub_get_data, JSON_UNESCAPED_UNICODE);
最后采用Curl请求,获取公钥。(go_curl函数文章后面提供)
go_curl($QueryKeyAPI_test,'POST',$formParams);
2.提交订单(一网通支付)
订单结构:
$tradeNo = time() . rand(1000, 9999); $timeExpire = "30"; //数据结构 $pay_get_data = [ 'version' => '1.0', 'charset' => 'UTF-8', 'signType' => $config['sign_type'], 'reqData' => [ 'dateTime' => date('YmdHis', $nowTime), 'branchNo' => $config['branch_no'], 'merchantNo' => $config['mch_id'], 'date' => date('Ymd', $nowTime), 'orderNo' => $tradeNo, 'amount' => "0.01", // 固定两位小数,最大11位整数 'expireTimeSpan' => $timeExpire, 'payNoticeUrl' => $config['notify_url'], //'payNoticePara' => '', 'returnUrl' => $config['return_url'], //'clientIP' => '', //'cardType' => $config['limit_pay'], // A:储蓄卡支付,即禁止信用卡支付 // 'agrNo' => '', // 'merchantSerialNo' => '', //'userID' => '', // 'mobile' => '', // 'lon' => '', // 'lat' => '', // 'riskLevel' => '', 'signNoticeUrl' => $config['sign_notify_url'], // 'signNoticePara' => '', ], ];
注释部分不是必填的,具体参考一网通官方接口说明。
获取请求报文:
$baResult1 = make_sign($config['mer_key'],$pay_get_data['reqData']); $pay_get_data['sign']=$baResult1; $formParams1['charset'] = 'UTF-8'; $formParams1['jsonRequestData']=json_encode($pay_get_data);
这里和取得公钥的方法不太一样,需要直接采用form表单的方式提交跳转(可使用js自动提交)
' />
结构无误的情况下,提交后自动跳转支付页面。
3.查询订单
$reqData = [ 'dateTime' => date('YmdHis', $nowTime), 'branchNo' => $config['branch_no'], 'merchantNo' => $config['mch_id'], 'date' => date('Ymd', time()), 'type' => 'B', // 'bankSerialNo' => '', 'orderNo' => $tradeNo ]; $baResult2 = make_sign($config['mer_key'],$reqData); $jsonRequestData = [ 'version' => '1.0', 'charset' => 'UTF-8', 'signType' => $config['sign_type'], 'sign' => $baResult2, 'reqData' => $reqData ]; $formParams2['charset'] = 'UTF-8'; $formParams2['jsonRequestData']=json_encode($jsonRequestData);
查询订单采用Type中的B类型,商户自己的订单编号,这里需要注意的是,如果要查询真实(测试)订单时,需要订单编号orderNo和支付时间date完全正确哦,如你查询今天的订单号,用了昨天的时间那就会查不到。(测试报告需要 查询1给正确订单和1个失败订单)
**注意事项:**
‘branch_no’ => ‘xxxx’, // 商户分行号,4位数字 ‘mch_id’ => ‘xxxx’, // 商户号,6位数字 ‘mer_key’ => ‘1234567890123456’, // 秘钥16位,包含大小写字母 数字
这3个参数需要联系一网通获取,服务器ip需要过一网通白名单ip,否则无法测试成功哦
**关于测试报告:**
招行一网通主要测试项目有4个,正常这4个测试通过(H5支付商户测试验收报告),就可以申请正式账号了。 分别是: CMB_test003CMB_test004 和 CMB_test008CMB_test009
3和4分别通过步骤2 提交2个订单,分别用储蓄卡和信用卡进行提交(一网通提供测试卡号)。 8输入3或4提交通过的订单,查询返回并截图。 9输入任意不存在订单号,截图就可以了
附录:
go_curl函数
//提交 function go_curl($url, $type, $data = false, &$err_msg = null, $timeout = 20, $cert_info = array()) { $type = strtoupper($type); if ($type == 'GET' && is_array($data)) { $data = http_build_query($data); } $option = array(); if ( $type == 'POST' ) { $option[CURLOPT_POST] = 1; } if ($data) { if ($type == 'POST') { $option[CURLOPT_POSTFIELDS] = $data; } elseif ($type == 'GET') { $url = strpos($url, '?') !== false ? $url.'&'.$data : $url.'?'.$data; } } $option[CURLOPT_URL] = $url; $option[CURLOPT_FOLLOWLOCATION] = TRUE; $option[CURLOPT_MAXREDIRS] = 4; $option[CURLOPT_RETURNTRANSFER] = TRUE; $option[CURLOPT_TIMEOUT] = $timeout; //设置证书信息 if(!empty($cert_info) && !empty($cert_info['cert_file'])) { $option[CURLOPT_SSLCERT] = $cert_info['cert_file']; $option[CURLOPT_SSLCERTPASSWD] = $cert_info['cert_pass']; $option[CURLOPT_SSLCERTTYPE] = $cert_info['cert_type']; } //设置CA if(!empty($cert_info['ca_file'])) { // 对认证证书来源的检查,0表示阻止对证书的合法性的检查。1需要设置CURLOPT_CAINFO $option[CURLOPT_SSL_VERIFYPEER] = 1; $option[CURLOPT_CAINFO] = $cert_info['ca_file']; } else { // 对认证证书来源的检查,0表示阻止对证书的合法性的检查。1需要设置CURLOPT_CAINFO $option[CURLOPT_SSL_VERIFYPEER] = 0; } $ch = curl_init(); curl_setopt_array($ch, $option); $response = curl_exec($ch); $curl_no = curl_errno($ch); $curl_err = curl_error($ch); curl_close($ch); // error_log if($curl_no > 0) { if($err_msg !== null) { $err_msg = '('.$curl_no.')'.$curl_err; } } return $response; }
本文为原创文章,已经发布到csdn等各大it媒体,转账请注明出处,谢谢!
以上代码可以Gitee上下载,地址:https://gitee.com/crx349/cmbchinademo
如果对您有帮助,麻烦给个Star吧,谢谢!