详解⼩程序⽀付流程与梳理
花了⼏天把⼩程序的⽀付模块接⼝写了⼀下,可能有着开发的⼀点经验,没有⼊太多的坑,在此我想记录⼀下整个流程。
⾸先先把⼩程序⽀付的图搬过来:
相信会来查百度的同学们基本都是对⽂档的说明不是很理解。我下⾯⼤概总结⼀下整个业务逻辑的过程。
⼩程序的商户系统⼀般是以接⼝的形式开发的,⼩程序通过调⽤与后端约定好的接⼝进⾏参数的传递以及数据的接收。在⼩程序⽀付这块,还需要跟服务器进⾏交互。过程⼤致是这样的:
⼀.⼩程序调⽤登录接⼝获取code,传递给商户服务器⽤来获取⽤户的openID
我们知道在平台中,同⼀个的openID都是不同的,它是⽤户⾝份识别的id,也就是说,我们通过openID来区分不同的⽤户,这个有开发基础的应该都很熟悉。为了知道谁在⽀付,我们需要先获取当前⽤户的openid,那么openID应该怎么获取呢?看下图:
1. ⼩程序调⽤wx.login() 获取临时登录凭证code ,并回传到开发者服务器。
2. 开发者服务器以code换取⽤户唯⼀标识openid 和会话密钥session_key。
看不懂吗?不急,听我慢慢解释,这个业务流程⼤致就是⾸先你得先在⼩程序的代码中调⽤wx.login()来向获取到code,拿到了之后把code通过request传给商户服务器,再由商户服务器通过骚操作来跟服务器要session_key和openID。
伪代码如下(⼩程序端):
getToken: function () {
//调⽤登录接⼝
wx.login({
success: function (res) {
var code = de;
url: 商户服务器接⼝地址,
data: {
code: code
},
method: 'POST',
success: function (res) {
wx.setStorageSync('token', ken); //存在⼩程序缓存中
},
fail: function (res) {
console.log(res.data);
}
})
}
})
}
调⽤这⼏⾏代码就可以向跟服务器要code,并且将code传到商户服务器中,记住这⾥最好使⽤po
st发送请求,安全性的东西我应该不⽤讲了,因为避免其他⼈滥⽤接⼝,于是我们使⽤token来进⾏验证。并将商户服务器返回的token存在⼩程序缓存中。
那么服务器端应该怎么做呢?
我门通过⼩程序提交的code,和⼩程序的APPID以及APPSECRET和拼接下列的url,并⽤curl进⾏get请求。
返回的数据是⼀个json对象,我门通过使⽤json_decode(JSON,true)解析为数组,数据包括⽤户的openID以及session_key,获取到了后我们应该将openID存⼊数据库中,它代表着⽤户的⾝份,那么令牌应该怎么⽣成呢。
⼆.token的⽣成以及缓存
我们根据⼀个⽤户表将id和openid联系起来,对应openID的id则是⽤户的uid,我们可以这么封装
//要缓存的数据数组
$cacheValue = $result; //包含openID和session_key
$cacheValue['uid'] =$uid; //⽤户id
$cacheValue['scope'] =ScopeEnum::User; //⽤户权限级别
缓存的⽅式我们可以选择redis,memcache,⽂件缓存等等,采⽤键值对(key-value)的⽅式进⾏存储,记得设置好过期时间。这⾥的key我们⽤token来赋值,token可以通过这样的⽅式进⾏⽣成:
//获取32位随机字符串
$str = getRandChar(32); //⾃定义⽅法⽣成32位随机串
//三组字符串进⾏md5加密
$timeStamp =$_SERVER['REQUEST_TIME_FLOAT'];
//salt
$salt = config('ken_salt'); //随机字符串
//返回token
return md5($str.$timeStamp.$salt);
这种算法基本保障了token的唯⼀性。因为值是我们获取到的openID和session_key所在的数组,所以需要将数组转成json才能存进去。以后的代码当我们需要openID或者uid等时可以直接通过取缓存的⽅式来取。
三,调⽤统⼀下单接⼝,获取prepay_id,再次签名
在你写完了订单操作后,如何让⽤户⽀付订单费⽤呢?这⾥就是重点了,我⼀步⼀步来说:
1.下载JS-SDK:
解压打开进⼊lib⽂件夹中:
我们需要将lib中的⽂件放到我们的框架中,例如我使⽤的是tp5,就放到extend下,最好是在extend下建个⼦⽂件夹。其中WxPay.Api.php是⼊⼝,WxPay.Config.php是配置⽂件。下好后需要改动⼀些地⽅。在WxPay.Config.php中修改下列的东西改成你的。
然后在WxPay.Api.php中require⼀下WxPay.Notify.php,如图:
在某个控制器或者服务层的代码先是⽤Loader::import()引⼊WxPay.Api.php,相当于五个都引⼊了。
2.调⽤统⼀下单api
这⾥要啰嗦的是,如何你写的是有关商品买卖的⼩程序,那么需要在⽀付前再次检测⼀下库存量,因
为⽤户下完订单后不⼀定马上就会付款,如果在付款的期间库存量没了便会出现问题。业务逻辑我就不说太多了,这取决于你写代码的严谨性。
在我们引⼊了上⾯那个⽂件后,先实例化这个类WxPayUnifiedOrder,把需要的参数通过调⽤对应的⽅法传⼊。
伪代码如下:
//调⽤⽀付统⼀下单接⼝
$wxOrderData = new \WxPayUnifiedOrder();
//设置相关参数
$wxOrderData->SetOut_trade_no($this->orderNO);
$wxOrderData->SetTrade_type('JSAPI');
$wxOrderData->SetTotal_fee($totalPrice * 100); //这⾥的价格单位是分
$wxOrderData->SetBody('Mc');
$wxOrderData->SetOpenid($openid);
$wxOrderData->SetNotify_url(config('secure.pay_back_url'));//⽀付回调
其中第⼀个是你的订单号,订单号的⽣成⽅法可以⾃定义,第⼆个是死参数,第三个是总订单价格,第四个是名称如果是中⽂的话要转码,第四个是openID,这个这时候就可以从缓存中取了。最后⼀个是⽀付回调,就是⽀付成功后要访问的地址。必须是公⽹能访问的,或者你使⽤ngrok来进⾏反向代理转发本地的服务器。
参数设置好了之后,就直接调⽤SDK的⽅法了
$wxOrder = \WxPayApi::unifiedOrder($wxOrderData);
如果参数没有错误的话,返回的数据中会含有prepay_id,这个是我们需要的参数。
3.再次签名
// 提交JSAPI输⼊对象
$jsApiPayData = new \WxPayJsApiPay();
/
/设置appid
$jsApiPayData->SetAppid(config('wx.app_id'));
//timeStamp
$jsApiPayData->SetTimeStamp((string)time());
//随机串
$randStr = md5(time().mt_rand(0,1000));
$jsApiPayData->SetNonceStr($randStr);
//数据报
$jsApiPayData->SetPackage('prepay_id='.$wxOrder['prepay_id']);
//类型
$jsApiPayData->SetSignType('MD5');
/
/⽣成签名
$sign = $jsApiPayData->MakeSign();
//获得签名数组
$signData = $jsApiPayData->GetValues();
//增加字段paySign
$signData['paySign']=$sign;
//删除signData中的app_Id字段
unset($signData['appId']);
return $signData;
再次签名完成后,就把五个参数返回给⼩程序。
四,⼩程序获取五个参数后,鉴权调起⽀付
伪代码(⼩程序端)
// 提交JSAPI输⼊对象
$jsApiPayData = new \WxPayJsApiPay();
//设置appid
$jsApiPayData->SetAppid(config('wx.app_id'));
//timeStamp
$jsApiPayData->SetTimeStamp((string)time());
//随机串
$randStr = md5(time().mt_rand(0,1000));
$jsApiPayData->SetNonceStr($randStr);
//数据报
$jsApiPayData->SetPackage('prepay_id='.$wxOrder['prepay_id']);
//类型
$jsApiPayData->SetSignType('MD5');
//⽣成签名
$sign = $jsApiPayData->MakeSign();
//获得签名数组
$signData = $jsApiPayData->GetValues();
//增加字段paySign
$signData['paySign']=$sign;
//删除signData中的app_Id字段
unset($signData['appId']);
return $signData;
写文章的小程序如果⼀切正常的话,在开发者⼯具就会显⽰这个⼆维码,
如果在真机上测试的话,就会直接弹出⽀付页⾯。⼩程序会直接显⽰⽀付成功或者失败的页⾯,然后服务器就会开始访问我们之前设置的⽀付回调地址来推送⽀付结果,根据结果可以来更新订单的状态。这⾥我就不写业务逻辑了,⼤概讲⼀下就好。
五,⽀付回调
实际上我们需要重写WxPayNotify类的NotifyProcess⽅法,这⾥记得Loader::impor()引⼊那个⼊⼝类。
/
**
*
* 回调⽅法⼊⼝,⼦类可重写该⽅法
* 注意:
* 1、回调超时时间为2s,建议⽤户使⽤异步处理流程,确认成功之后⽴刻回复服务器
* 2、服务器在调⽤失败或者接到回包为⾮确认包的时候,会发起重试,需确保你的回调是可以重⼊
* @param array $data 回调解释出的参数
* @param string $msg 如果回调处理失败,可以将错误信息输出到该⽅法
* @return true 回调出来完成不需要继续回调,false回调处理未完成需要继续回调
*/
public function NotifyProcess($data, &$msg)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。