• 微信小程序实现微信支付功能流程


    微信小程序实现微信支付功能流程

    微信支付:

     https://pay.weixin.qq.com/wiki/doc/api/index.html

    图片说明

    进行选择接入

    图片说明

    图片说明

    步骤:

    小程序调用登录接口,获取用户的openidwx.login(object), 通过调用接口获取登录凭证code进行获取登录用户信息,包含用户的唯一标识(openid)以及本次登录的会话密钥(session_key).

    code获取session_key, 这是一个https接口,开发者服务器使用登录凭证code获取session_keyopenid.其中session_key是对用户数据进行保密的密钥.为了安全,不能将session_key在网络上传输.

    图片说明

    获取的openid

    商户在小程序中先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。其实微信是提供java,net,php三种语言的封装包。

    https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

    图片说明

    微信小程序-支付

    http://www.cnblogs.com/jcscript/p/6126722.html

    需要支付的perpay_id

    wx.requestPayment(OBJECT)-微信支付

    参数类型必填说明
    timeStampString时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
    nonceStrString随机字符串。
    packageString统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=***
    signTypeString签名算法,暂支持 MD5
    paySignString签名,具体签名方案参见小程序支付接口文档;

    wx.requestPayment({
       "timeStamp": "",
       "nonceStr": "",
       "package": "",
       "signType": "MD5",
       "paySign": "",
       "success":function(res){
       },
       "fail":function(res){
       }
    })

    获取支付idres_pay, 仅返回了perpay_id,还有随机字符串和签名

    1. 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=***

    2. 签名,具体签名方案参见小程序支付接口文档

    踩坑:

    图片说明

    图片说明

    小程序支付->小程序调用起支付API

    图片说明

    微信小程序API同理

    图片说明

    https://developers.weixin.qq.com/miniprogram/dev/api/wx.requestPayment.html

    图片说明

    // 调起支付签名
    function MixedencryMD5(res_paydata,randomString,timeStamp) {
      return "appId=" + config.appid + "&nonceStr=" + randomString + "&package=prepay_id=" + res_paydata + "&signType=MD5" + "&timeStamp=" + timeStamp + "&key=" + config.key;  
    }
    // 时间戳
    function timeStamp() {
      return parseInt(new Date().getTime() / 1000) + ''
    }
    /* 随机数 */
    function randomString() {
      var chars = 'A2345678';    
      var maxPos = chars.length;
      var pwd = '';
      for (var i = 0; i < 32; i++) {
        pwd += chars.charAt(Math.floor(Math.random() * maxPos));
      }
      return pwd;
    }

    图片说明

    注意: 时间戳和随机字符串,保证生成一次

    微信支付开发文档-普通商户

    https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=1_1

    图片说明

    图片说明

    开通微信支付和微信商户号,获取当前用户的openid,通过调用wx.login方法,可以得到用户的code,然后开发者服务器使用登录凭证code获取openid.然后在获取prepay_id和支付签名验证paySign

    `appid`: "", // 公众号名称,由商户传入
    `timeStamp`: "", // 时间
    `nonceStr`: "", // 随机串
    'package': 'prepay_id=',
    'signType`: 'MD5'; // 微信签名方式,
    'paySign': ""; // 微信签名

    小程序通过wx.requestPayment方法调用起支付功能.prepay_id的获取和签名paySign的获取.

    图片说明

    在小程序后台,申请微信支付,认证以后,微信支付申请审核通过后,商户在申请资料填写的邮箱中收取到由微信支付小助手发送的邮件,此邮件包含开发时需要使用的支付账户信息。

    图片说明

    图片说明

    协议规则-商户接入微信支付

    图片说明

    安全规范

    图片说明

    appid:  wxd
    mch_id: 100
    device_info:    10
    body:   test
    nonce_str:  ibA

    第一步:对参数按照key=value的格式

    stringA="appid=wx&body=test&device_info=10&mch_id=10100&nonce_str=ibJA";

    第二步:拼接API密钥

    stringSignTemp=stringA+"&key=" //注:key为商户平台设置的密钥key
    
    sign=MD5(stringSignTemp).toUpperCase()="" //注:MD5签名方式
    
    sign=hash_hmac("sha256",stringSignTemp,key).toUpperCase()="" //注:HMAC-SHA256签名方式

    最终得到最终发送的数据

    <xml>
    <appid>wx</appid>
    <mch_id>1000</mch_id>
    <device_info>1</device_info>
    <body>test</body>
    <nonce_str>ibuA</nonce_str>
    <sign>9A0A89CF3B7</sign>
    </xml>

    小程序支付

    开放模式介绍-appidmch_id成对使用

    微信支付开放的能力分2大类:普通模式和服务商模式

    微信支付基础账号模型-普通模式

    图片说明

    普通服务商微信支付资金清算流程

    图片说明

    JSAPI 或 JSSDK 调起微信支付

    图片说明

    小程序支付模式

    第一步开通微信支付功能,绑定微信支付商户号.

    appid 小程序appid
    mch_id 所绑定的商户号中的 mch_id
    trade_type 请填写"JSAPI"
    openid 使用 "wx.login" 接口获得的 openid

    业务说明

    1. 账号申请指引

    2. 进行微信认证

    小程序申请微信认证
    认证入口:登录小程序—设置—基本设置—微信认证—详情

    图片说明

    小程序申请微信支付

    图片说明

    小程序绑定微信开放平台帐号
    绑定小程序流程说明:登录微信开放平台(open.weixin.qq.com)—管理中心—公众帐号—绑定公众帐号

    公众号关联小程序
    关联流程:
    登录公众号后台-小程序-小程序管理-添加-关联小程序

    开通微信支付后,申请或复用微信支付商户号,新申请微信支付商户号或绑定一个已有的微信支付商户号,开通指引:

    http://kf.qq.com/faq/140225MveaUz161230yqiIby.html

    图片说明

    注意事项:

    图片说明

    业务流程

    小程序支付的流程图如下:

    图片说明

    图片说明

    1、【[小程序登录API](https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html?t=20161122)】

    2、【[统一下单API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1)】

    3、【[再次签名](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3)】

    4、【[支付结果通知API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7)】

    5、【[查询订单API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_2)】

    开发步骤

    图片说明

    HTTPS服务器配置

    https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=10_4

    图片说明

    小程序绑定已有商户号开通微信支付http://kf.qq.com/faq/140225MveaUz161230yqiIby.html

    小程序调起支付API

    https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5

    图片说明

    示例代码:

    wx.requestPayment(
    {
    'timeStamp': '',
    'nonceStr': '',
    'package': '',
    'signType': 'MD5',
    'paySign': '',
    'success':function(res){},
    'fail':function(res){},
    'complete':function(res){}
    })

    商户平台安全使用

    图片说明

    小程序

    案例:

    /* 微信支付 */
      goWxPay: function () {
        var that = this;
        wx.login({
          success: function (res) {
            console.log("获取login code",res.code);
            that.getOpenId(res.code);
          }
        });
      },
     
      /* 获取openId */
      getOpenId: function (code) {
        var that = this;
        wx.request({
          url: "" + code, 
          method: 'GET',
          success: function (res) {
            that.unitedPayRequest(res.data.openid);
          },
          fail: function () {
    
          },
          complete: function () {
    
          }
        });
      },
     
      /*统一支付接口*/
      unitedPayRequest: function(openid){
        var that=this;
        //统一支付签名
        var appid = '';//appid必填
        var body = '';//商品名必填
        var mch_id = '';//商户号必填
        var nonce_str = util.randomString();//随机字符串,不长于32位。  
        var notify_url = '';//通知地址必填
        var total_fee = parseInt(0.01 * 100); //价格,这是一分钱
        var trade_type = "JSAPI";
        var key = ''; //商户key必填,在商户后台获得
        var out_trade_no = '';//自定义订单号必填
     
        var unifiedPayment = 'appid=' + appid + '&body=' + body + '&mch_id=' + mch_id + '&nonce_str=' + nonce_str + '&notify_url=' + notify_url + '&openid=' + openid + '&out_trade_no=' + out_trade_no + '&total_fee=' + total_fee + '™_type=' + trade_type + '&key=' + key;
        console.log("unifiedPayment", unifiedPayment);
        var sign = md5.md5(unifiedPayment).toUpperCase();
        console.log("签名md5", sign);
     
        //封装统一支付xml参数
        var formData = "<xml>";
        formData += "<appid>" + appid + "</appid>";
        formData += "<body>" + body + "</body>";
        formData += "<mch_id>" + mch_id + "</mch_id>";
        formData += "<nonce_str>" + nonce_str + "</nonce_str>";
        formData += "<notify_url>" + notify_url + "</notify_url>";
        formData += "<openid>" + openid + "</openid>";
        formData += "<out_trade_no>" + that.data.ordernum + "</out_trade_no>";
        formData += "<total_fee>" + total_fee + "</total_fee>";
        formData += "<trade_type>" + trade_type + "</trade_type>";
        formData += "<sign>" + sign + "</sign>";
        formData += "</xml>";
        console.log("formData", formData);
        //统一支付
        wx.request({
          url: '', 
          method: 'POST',
          head: 'application/x-www-form-urlencoded',
          data: formData, //设置请求的 header
          success: function (res) {
            console.log("返回商户", res.data);
            var result_code = util.getXMLNodeValue('result_code', res.data.toString("utf-8"));
            var resultCode = result_code.split('[')[2].split(']')[0];
            if (resultCode == 'FAIL') {
              var err_code_des = util.getXMLNodeValue('err_code_des', res.data.toString("utf-8"));
              var errDes = err_code_des.split('[')[2].split(']')[0];
              wx.showToast({
                title: errDes,
                icon: 'none',
                duration: 3000
              })
            } else {
              //发起支付
              var prepay_id = util.getXMLNodeValue('prepay_id', res.data.toString("utf-8"));
              var tmp = prepay_id.split('[');
              var tmp1 = tmp[2].split(']');
              //签名  
              var key = '';//商户key必填,在商户后台获得
              var appId = '';//appid必填
              var timeStamp = util.createTimeStamp();
              var nonceStr = util.randomString();
              var stringSignTemp = "appId=" + appId + "&nonceStr=" + nonceStr + "&package=prepay_id=" + tmp1[0] + "&signType=MD5&timeStamp=" + timeStamp + "&key=" + key;
              console.log("签名字符串", stringSignTemp);
              var sign = md5.md5(stringSignTemp).toUpperCase();
              console.log("签名", sign);
              var param = { "timeStamp": timeStamp, "package": 'prepay_id=' + tmp1[0], "paySign": sign, "signType": "MD5", "nonceStr": nonceStr }
              console.log("param小程序支付接口参数", param);
              that.processPay(param);
            }
          },
        })
      },
     
      /* 小程序支付 */
      processPay: function (param) {
        wx.requestPayment({
          timeStamp: param.timeStamp,
          nonceStr: param.nonceStr,
          package: param.package,
          signType: param.signType,
          paySign: param.paySign,
          success: function (res) {
            console.log("wx.requestPayment返回信息",res);
            wx.showModal({
              title: '支付成功',
              content: '官方号中收到支付凭证',
              showCancel: false,
              success: function (res) {
                if (res.confirm) {
                } else if (res.cancel) {
                }
              }
            })
          },
          fail: function () {
            console.log("支付失败");
          },
          complete: function () {
            console.log("支付完成");
          }
        })
      }

    客户端js

    wx.request({
    url:'',
    header:{
    'Content-Type':'application/x-www-form-urlencoded'
    },
    method:'POST',
    success:function(res){
    console.log(res.data);
    console.log('调起支付');
    wx.requestPayment({
    'timeStamp': res.data.timeStamp,
    'nonceStr': res.data.nonceStr,
    'package': res.data.package,
    'signType':'MD5',
    'paySign': res.data.paySign,
    'success':function(res){
    console.log('success');
    wx.showToast({
    title:'支付成功',
    icon:'success',
    duration:3000
    });
    },
    'fail':function(res){
    console.log('fail');
    },
    'complete':function(res){
    console.log('complete');
    }
    });
    },
    fail:function(res){
    console.log(res.data)
    }
    });

    先开通微信支付商户

    在小程序后台,点击微信支付,申请开通,选择新申请,

    统一下单:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1

    接口链接
    URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

    图片说明

    举例如下:

    <xml>
       <appid>wx2421b1c4370ec43b</appid>
       <attach>支付测试</attach>
       <body>JSAPI支付测试</body>
       <mch_id>10000100</mch_id>
       <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail>
       <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
       <notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>
       <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
       <out_trade_no>1415659990</out_trade_no>
       <spbill_create_ip>14.23.150.211</spbill_create_ip>
       <total_fee>1</total_fee>
       <trade_type>JSAPI</trade_type>
       <sign>0CB01533B8C1EF103065174F50BCA001</sign>
    </xml>

    微信支付的流程:

    1. 获取用户code

    2. 获取用户openid

    3. 服务器上请求微信的统一下单接口,获取prepay_id

    微信支付的整个流程:

    获取用户的code值,请求用户的openid.

    //app.js
    App({
      onLaunch: function() {
        wx.login({
          success: function(res) {
            if (res.code) {
              //发起网络请求
              wx.request({
                url: 'https://test.com/onLogin',
                data: {
                  code: res.code
                }
              })
            } else {
              console.log('获取用户登录态失败!' + res.errMsg)
            }
          }
        });
      }
    })

    接着服务端来请求微信的地址:(参考微信官方api)

    https://api.weixin.qq.com/sns/jscode2session

    public Map<String,Object> onLogin(String code){
            Map<String,Object>result=new HashMap<>();
            String url=ConstantUtils.getSessionKeyUrl+"?appid="+ ConstantUtils.appId+
                    "&secret="+ConstantUtils.secret+"&js_code="+code+"&grant_type="+ConstantUtils.grantType;
            JSONObject httpResult=HttpUtils.httpGet(url);
            result.put("openid",httpResult.get("openid"));
            result.put("session_key",httpResult.get("session_key"));
            result.put("expires_in",httpResult.get("expires_in"));
            return  result;
        }

    统一下单的接口,获取prepay_id字段值

    https://api.mch.weixin.qq.com/pay/unifiedorder

    public Map<String,Object> createOrder(String openId){
            Map<String,Object>result=new HashMap<>();
            result.put("status","1");
            result.put("payType","weixin");
            result.put("orderId","123456");
            String formData=orderService.commitData(openId);
            String httpResult = HttpUtils.httpXMLPost(ConstantUtils.createOrderUrl,formData);
            try {
                Map<String, String> resultMap = WXPayUtil.xmlToMap(httpResult);
                result.put("package", "prepay_id=" + resultMap.get("prepay_id"));
                result.put("nonceStr",resultMap.get("nonce_str"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            String times= WXPayUtil.getCurrentTimestamp()+"";
            result.put("timeStamp",times);
            Map<String, String> packageParams = new HashMap<String ,String>();
            packageParams.put("appId", ConstantUtils.appId);
            packageParams.put("signType", ConstantUtils.signType);
            packageParams.put("nonceStr",result.get("nonceStr")+"");
            packageParams.put("timeStamp",times);
            packageParams.put("package", result.get("package")+"");//商户订单号
            String sign="";
            try {
                sign= WXPayUtil.generateSignature(packageParams, ConstantUtils.key);
            } catch (Exception e) {
                e.printStackTrace();
            }
            result.put("paySign",sign);
            return result;
        }

    WXPayUtil工具类是微信官方demo中的工具类.

    可以JAVA后台实现小程序支付

    图片说明

    调用支付统一下单API来获取prepay_id
    小程序调支付数据需要签名的字段appIdtimeStampnonceStrpackage再次签名.

    微信公众平台支付接口调试工具

    https://pay.weixin.qq.com/wiki/tools/signverify/

    WXPayUtil.java

    https://download.csdn.net/download/by965738071/10389430

    代码

    开通微信支付功能,需要商户号,appidappsecretopenid

    小程序:

    参考

    https://blog.csdn.net/fredrik/article/details/79697963

    pay:function(){
    var that=this
    wx.getStorage({
    key: 'openid',
    success: function(res) {
    wx.request({
    url: url + 'Wx_Pay',
    data: {
    //用户的openid
    openid:res.data,
    fee: that.data.totalPrice, //支付金额
    details: that.data.goodsList[0].goods_name,//支付商品的名称
    },
    success:function(result){
    if(result.data){
    wx.requestPayment({
    timeStamp: result.data['timeStamp'],
    nonceStr: result.data['nonceStr'],
    package: result.data['package'],
    signType: 'MD5',
    paySign: result.data['paySign'],
    'success':function(successret){
    console.log('支付成功');
    //获取支付用户的信息
    wx.getStorage({
    key: 'userInfo',
    success: function (getuser) {
    wx.request({
    url: url + 'Wx_AddOrder',
    data: {
    uname: getuser.data.nickName,
    goods: that.data.goodsList[0].goods_name,
    price: that.data.totalPrice,
    openid:res.data,
    },
    success: function (lastreturn) {
    console.log("存取成功");
    }
    })
    },
    })
    },'fail':function(res){
    }
    })
    }
    }
    })
    },
    })
    },

    支付实现

    图片说明

    图片说明

    图片说明

    图片说明

    小程序端代码:

    wx.requestPayment({
       'timeStamp': '',
       'nonceStr': '',
       'package': '',
       'signType': 'MD5',
       'paySign': '',
       'success':function(res){
       },
       'fail':function(res){
       }
    })

    小程序端代码如下:

    pay:function(_payInfo,success,fail){
        var payInfo = {
            body:'',
            total_fee:0,
            order_sn:''
        }
        Object.assign(payInfo, _payInfo);
        if(payInfo.body.length==0){
            wx.showToast({
                title:'信息描述错误'
            })
            return false;
        }
        if(payInfo.total_fee==0){
            wx.showToast({
                title:'金额不能0'
            })
            return false; 
        }
        if(payInfo.order_sn.length==0){
            wx.showToast({
                title:'订单号不能为空'
            })
            return false; 
        }
        var This = this;
        This.getOpenid(function(openid){
            payInfo.openid=openid;
            This.request({
                url:'api/pay/prepay',
                data:payInfo,
                success:function(res){
                    var data = res.data;
                    console.log(data);
                    if(!data.status){
                        wx.showToast({
                            title:data['errmsg']
                        })
                        return false;
                    }
                    This.request({
                        url:'api/pay/pay',
                        data:{prepay_id:data.data.data.prepay_id},
                        success:function(_payResult){
                            var payResult = _payResult.data;
                            console.log(payResult);
                            wx.requestPayment({
                                'timeStamp': payResult.timeStamp.toString(),
                                'nonceStr': payResult.nonceStr,
                                'package': payResult.package,
                                'signType': payResult.signType,
                                'paySign': payResult.paySign,
                                'success': function (succ) {
                                    success&&success(succ);
                                },
                                'fail': function (err) {
                                    fail&&fail(err);
                                },
                                'complete': function (comp) { 
     
                                }
                            }) 
                        }
                    })
                }
            })
        })
    }

    开通微信支付和微信商户号

    获得用户的openid

    wx.login({
          success: function(res) {
            if (res.code) {
              wx.request({
                url: 'https://yourwebsit/onLogin',
                method: 'POST',
                data: {
                  code: res.code
                },
                success: function(res) {
                    var openid = res.data.openid;
                },
                fail: function(err) {
                    console.log(err)
                }
              })
            } else {
              console.log('获取用户登录态失败!' + res.errMsg)
            }
          }
        });
    
    var code = req.param("code");
            request({
                url: "https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code",
                method: 'GET'
            }, function(err, response, body) {
                if (!err && response.statusCode == 200) {
                    res.json(JSON.parse(body));
                }
            });

    获取prepay_id和支付签名验证paySign

    图片说明

    通过wx.requestPayment方法来调起支付功能

    图片说明

    prepay_id的获取和签名paySign,是从小程序请求后台来的.

    图片说明

    第一步:调用wx.login(object)获取用户的code,code换取session_key,

    微信的第三个接口,统一下单,获取prepay_id,第四个接口,wx.requestPayment(object),成功后,请求支付后的结果.

    先执行wx.login

    小程序代码:

    <view>
    <button bindtap='wxpay' class='css'>发起支付</button>
    </view>
    // js
    var app=getApp();
    Page({
      wxpay: function(){
        var code=app.code;
        wx.request({
          url: SERVER_PATH+'wxpayapi/, 
          data: {
            code: code
          },
          header: {
            'content-type': 'application/json' 
          },
          success: function (res) {
            console.log(res.data);
            var data=res.data;
            wx.requestPayment({
              'timeStamp': data.timeStamp,
              'nonceStr': data.nonceStr,
              'package': data.package,
              'signType': 'MD5',
              'paySign': data.paySign,
              'success': function (res) {
                console.log("支付成功!")
              },
              'fail': function (res) {
              }
            })
          }
        })
      }
    })

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

    图片说明

    实例参考地址:

    https://pan.baidu.com/s/1pKLgG8z
    https://pan.baidu.com/s/1nuBH0EX

    达叔小生:往后余生,唯独有你
    You and me, we are family !
    90后帅气小伙,良好的开发习惯;独立思考的能力;主动并且善于沟通
    简书博客: 达叔小生
    https://www.jianshu.com/u/c785ece603d1

    结语

    • 下面我将继续对 其他知识 深入讲解 ,有兴趣可以继续关注

    • 小礼物走一走 or 点赞

    这是一个有质量,有态度的公众号

    喜欢本文的朋友们

    欢迎长按下图关注订阅号

    收看更多精彩内容

  • 相关阅读:
    023 AQS--JUC的核心
    022 Future接口
    021 Callable接口
    020 线程的综合考虑
    019 线程协作
    命令,lldb,llvm,gdb,gcc,
    @class,import,
    arc,自动引用计数,
    写在哪里,
    40岁生日,
  • 原文地址:https://www.cnblogs.com/dashucoding/p/12222882.html
Copyright © 2020-2023  润新知