Detailed micro-channel applet payment process

Forwarding bloggers https://blog.csdn.net/qq_38378384/article/details/80882980

  It took a few days to pay a small program module interface to write a bit, might have a little more experience of developing public number, not too much into the pit, and I wanted to record it through the process.

First, micro-letter first chart applet to pay to move over:

I believe it will come check Baidu students are basically of the documentation is not very understanding. I probably below summarize the entire business process logic.

Merchant system micro-channel generally in the form of small programs developed interface, the applet by calling the interface with the rear end of the good reception and data transmission parameters of the agreement. In this small program payments, you need to keep up the WeChat server interaction. Process roughly like this:

A small program invokes the login interface to obtain code, passed to the merchant server to get the user's openID

 We know that the micro-channel platform, with a public openID number is different, it is the identity of the user id, that is to say, we have to distinguish between different users through openID, this has developed micro-channel basis should be very familiar. In order to know who to pay, we need to get the current user's openid, then how openID should get it? Look:

 

  1. Applet calls wx.login () to obtain temporary registration certificate code, and the developers back to the server.

  2. Developers exchange server code that uniquely identifies the user and session key openid session_key.

Can not read it? Do not worry, listen to me please explain this business process is generally the first thing you have to call in the code wx.login small program () to get the code to the micro letter, then got the code request to pass through the merchant server, and then to come session_key and openID with micro-channel server by the merchant server via Sao operation.

Pseudo code (applets side):

  1.  
    getToken: function () {
  2.  
    // Call Log Interface
  3.  
    wx.login({
  4.  
    success: function (res) {
  5.  
    var code = res.code;
  6.  
    wx.request({
  7.  
    url: 商户服务器接口地址,
  8.  
    data: {
  9.  
    code: code
  10.  
    },
  11.  
    method: 'POST',
  12.  
    success: function (res) {
  13.  
    wx.setStorageSync( 'token', res.data.token); //存在小程序缓存中
  14.  
    },
  15.  
    fail: function (res) {
  16.  
    console.log(res.data);
  17.  
    }
  18.  
    })
  19.  
    }
  20.  
    })
  21.  
    }

调用这几行代码就可以向跟微信服务器要code,并且将code传到商户服务器中,记住这里最好使用post发送请求,安全性的东西我应该不用讲了,因为避免其他人滥用接口,于是我们使用token来进行验证。并将商户服务器返回的token存在小程序缓存中。

那么服务器端应该怎么做呢?

我门通过小程序提交的code,和小程序的APPID以及APPSECRET和拼接下列的url,并用curl进行get请求。

 

https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

返回的数据是一个json对象,我门通过使用json_decode(JSON,true)解析为数组,数据包括用户的openID以及session_key,获取到了后我们应该将openID存入数据库中,它代表着用户的身份,那么令牌应该怎么生成呢。

二.token的生成以及缓存

我们根据一个用户表将id和openid联系起来,对应openID的id则是用户的uid,我们可以这么封装

  1.  
    //要缓存的数据数组
  2.  
    $cacheValue = $result; //包含openID和session_key
  3.  
    $cacheValue[ 'uid'] =$uid; //用户id
  4.  
     
  5.  
    $cacheValue[ 'scope'] =ScopeEnum::User; //用户权限级别

缓存的方式我们可以选择redis,memcache, 文件缓存等等,采用键值对(key-value)的方式进行存储,记得设置好过期时间。这里的key我们用token来赋值,token可以通过这样的方式进行生成:

  1.  
    //获取32位随机字符串
  2.  
    $str = getRandChar( 32); //自定义方法生成32位随机串
  3.  
    //三组字符串进行md5加密
  4.  
    $timeStamp =$_SERVER[ 'REQUEST_TIME_FLOAT'];
  5.  
    //salt
  6.  
    $salt = config( 'secure.token_salt'); //随机字符串
  7.  
    //返回token
  8.  
     
  9.  
    return md5($str.$timeStamp.$salt);

这种算法基本保障了token的唯一性。因为值是我们获取到的openID和session_key所在的数组,所以需要将数组转成json才能存进去。以后的代码当我们需要openID或者uid等时可以直接通过取缓存的方式来取。

三,调用统一下单接口,获取prepay_id,再次签名

 在你写完了订单操作后,如何让用户支付订单费用呢?这里就是重点了,我一步一步来说:

1.下载微信JS-SDK:

(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1)

解压打开进入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,把需要的参数通过调用对应的方法传入。

伪代码如下:

  1.  
    //调用微信支付统一下单接口
  2.  
    $wxOrderData = new \WxPayUnifiedOrder();
  3.  
    //设置相关参数
  4.  
    $wxOrderData->SetOut_trade_no( $this->orderNO);
  5.  
    $wxOrderData->SetTrade_type( 'JSAPI');
  6.  
    wxOrderData- $> SetTotal_fee (the totalPrice * $ 100); // here is the unit price points
  7.  
    $wxOrderData->SetBody( 'Mc');
  8.  
    $wxOrderData->SetOpenid($openid);
  9.  
    wxOrderData- $> SetNotify_url (config ( 'secure.pay_back_url')); // callback pay

The first one is your order number, order number generation method can be customized, and the second parameter is dead, and the third is the total order price, and the fourth is the name if it is Chinese, then be transcoded, the fourth is openID, that this time we can take from the cache. The last one is paid callback is successful micro-channel payment address to be accessed. It must be able to access the public network, or if you use ngrok to reverse proxy server forwards the local.

After the parameters have been set up, call the SDK direct method

 $wxOrder = \WxPayApi::unifiedOrder($wxOrderData);
If the parameter is not wrong, the data returned will contain prepay_id, this is the parameter we need.

 

3. signature again
  1.  
    // submit JSAPI input object
  2.  
    $jsApiPayData = new \WxPayJsApiPay();
  3.  
    // set appid
  4.  
    $jsApiPayData->SetAppid(config( 'wx.app_id'));
  5.  
    //timeStamp
  6.  
    $jsApiPayData->SetTimeStamp((string)time());
  7.  
    // random string
  8.  
    $randStr = md5(time().mt_rand( 0,1000));
  9.  
    $jsApiPayData->SetNonceStr($randStr);
  10.  
    //数据报
  11.  
    $jsApiPayData->SetPackage( 'prepay_id='.$wxOrder['prepay_id']);
  12.  
    //类型
  13.  
    $jsApiPayData->SetSignType( 'MD5');
  14.  
    //生成签名
  15.  
    $sign = $jsApiPayData->MakeSign();
  16.  
    //获得签名数组
  17.  
    $signData = $jsApiPayData->GetValues();
  18.  
    //增加字段paySign
  19.  
    $signData[ 'paySign']=$sign;
  20.  
    //删除signData中的app_Id字段
  21.  
    unset($signData['appId']);
  22.  
    return $signData;

再次签名完成后,就把五个参数返回给小程序。

四,小程序获取五个参数后,鉴权调起支付

伪代码(小程序端)

  1.  
    pay: function () {
  2.  
    var token = wx.getStorageSync('token');
  3.  
    var that = this;
  4.  
     
  5.  
    wx.request({
  6.  
    url: baseUrl + '/order',
  7.  
    header: {
  8.  
    token: token
  9.  
    },
  10.  
    data: { //产品的数据
  11.  
    products:
  12.  
    [
  13.  
    {
  14.  
    product_id: 1, count: 1
  15.  
    },
  16.  
     
  17.  
    {
  18.  
    product_id: 2, count: 1
  19.  
    }
  20.  
    ]
  21.  
    },
  22.  
    method: 'POST',
  23.  
    success: function (res) {
  24.  
    console.log(res.data);
  25.  
    if (res.data.pass) {
  26.  
    wx.setStorageSync( 'order_id', res.data.order_id);
  27.  
    that.getPreOrder(token, res.data.order_id); //调用getPreOrder
  28.  
    }
  29.  
    else {
  30.  
    console.log('订单未创建成功');
  31.  
    }
  32.  
    }
  33.  
    })
  34.  
    },
  35.  
     
  36.  
    getPreOrder: function (token, orderID) {
  37.  
    if (token) {
  38.  
    wx.request({
  39.  
    url: baseUrl + '/pay/pre_order',
  40.  
    method: 'POST',
  41.  
    header: {
  42.  
    token: token
  43.  
    },
  44.  
    data: {
  45.  
    id: orderID
  46.  
    },
  47.  
    success: function (res) {
  48.  
    var preData = res.data;
  49.  
    console.log(preData);
  50.  
     
  51.  
    wx.requestPayment({ //请求支付
  52.  
    timeStamp: preData.timeStamp.toString(),
  53.  
    nonceStr: preData.nonceStr,
  54.  
    package: preData.package,
  55.  
    signType: preData.signType,
  56.  
    paySign: preData.paySign,
  57.  
    success: function (res) {
  58.  
    console.log(res.data);
  59.  
    },
  60.  
    fail: function (error) {
  61.  
    console.log(error);
  62.  
    }
  63.  
    })
  64.  
    }
  65.  
    })
  66.  
    }
  67.  
    },

如果一切正常的话,在微信开发者工具就会显示这个二维码,

如果在真机上测试的话,就会直接弹出支付页面。小程序会直接显示支付成功或者失败的页面,然后微信服务器就会开始访问我们之前设置的支付回调地址来推送支付结果,根据结果可以来更新订单的状态。这里我就不写业务逻辑了,大概讲一下就好。

五,支付回调

实际上我们需要重写WxPayNotify类的NotifyProcess方法,这里记得Loader::impor()引入那个入口类。

  1.  
    /**
  2.  
    *
  3.  
    * 回调方法入口,子类可重写该方法
  4.  
    * 注意:
  5.  
    * 1、微信回调超时时间为2s,建议用户使用异步处理流程,确认成功之后立刻回复微信服务器
  6.  
    * 2、微信服务器在调用失败或者接到回包为非确认包的时候,会发起重试,需确保你的回调是可以重入
  7.  
    * @param array $data 回调解释出的参数
  8.  
    * @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
  9.  
    * @return true 回调出来完成不需要继续回调,false回调处理未完成需要继续回调
  10.  
    */
  11.  
    public function NotifyProcess($data, &$msg)
  12.  
    {
  13.  
    //TODO 用户基础该类之后需要重写该方法,成功的时候返回true,失败返回false
  14.  
    return true;
  15.  
    }

  也就是说你需要写个新类继承WxPayNotify,再重写NotifyProcess方法,根据检查$data['result_code']是否为SUCCESS可以判断成功与否,成功的话你可以根据业务需求写业务逻辑,最后return true 即可。这时候会想,我重写了这个方法后微信怎么调用呢,其实这里微信不是要直接调用这个方法,你应该在微信支付回调的方法中实例化这个新类,然后根据获得的对象去调用Handle()方法。$obj = new 新类(),$obj->Handle()。

Guess you like

Origin www.cnblogs.com/class1/p/11266964.html