zoukankan      html  css  js  c++  java
  • 微信小程序 + nodeJs(loopback) 实现支付

    实现小程序的支付,首先需要去微信官网先了解一下微信小程序支付相关接口文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1

    微信支付首先需要调用微信的统一下单接口,返回微信支付接口需要数据。具体参数参考:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

    在后端服务中,提供一个小程序前端调用的订单接口,生成预定单并访问微信统一下单接口返回微信接口数据,具体服务端代码如下:

    module.exports = (req, res) => {
      // TODO replace the codes bellow and add your own codes here
      const wx_app_id = server.get('wx-app-id');
        let pay_info = {
            [wx_app_id]: { // 定义能支付的商户,可能存在多个
                mch_id: server.get('wx-mch-id'),
                pay_key: server.get('wx-pay-key') 
            }
        }if(!(req.body.appid in pay_info)) {
            res.send({
                successed: false,
                message: '商户不支持支付',
                datalist: '暂不支持支付的appid'
            });
            return
        }
        let sendtowx = {
            appid: req.body.appid,
            mch_id: pay_info[req.body.appid].mch_id,
            nonce_str: moment().valueOf(),
            body: req.body.body,
            // detail: req.body.detail,    
            // attach: req.body.attach,
            out_trade_no: getOrderNo(),   //订单在同一商家不能重复
            total_fee: req.body.total_fee,
            spbill_create_ip: req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress,
            notify_url: req.body.notify_url,  // 订单支付反馈通知接口,一般做修改订单完成状态用,微信支付成功后会在后台调用
            trade_type: 'JSAPI',
            openid: req.body.openid
        }
        sendtowx.sign = wx_sign(sendtowx, pay_info[req.body.appid].pay_key);  //生成MD5加密字符,传入字段不能有undefined。否则会报签名错误
    
        let request_str = '<xml>'
        for (let item in sendtowx) {
            request_str = request_str + '<' + item + '>'
            request_str = request_str + sendtowx[item]
            request_str = request_str + '</' + item + '>'
        }
        request_str = request_str + '</xml>'
        console.log('request_str:', request_str);
        const AppOrder = server.models.AppOrder;
        AppOrder.findOrCreate({where:req.body.where},{  // 首先创建系统订单,此时状态为待支付
            status:"0",
            pay_price: sendtowx.total_fee/100,
            order_no: sendtowx.out_trade_no
        }, function(err, data, created) {
            console.log(data,created,'s;s/');
            if (err) {
              console.log(err);
            } else if(created){
                console.log("创建预付订单成功",data);
              request.post(                    // 调用微信支付统一下单接口,返回微信预订单数据
                {
                  url : 'https://api.mch.weixin.qq.com/pay/unifiedorder',
                  // headers: {
                  // 'Content-Type':'text/xml; charset=utf-8',
                  // 'Content-Length': data.length
                  // },
                  body: request_str,
                  rejectUnauthorized: false
                }, function(err, httpResponse, body){
                  // 请求完成之后的回调函数    
                    console.log(body)
                    parseString(body, {explicitArray:false}, function (err, result) {
                        let res_body = { }
                        if(result.xml.return_code == 'SUCCESS') {
                            res_body.successed = true
                            res_body.message = 'ok'
                            let temp = {
                                appId: result.xml.appid,
                                timeStamp: moment().format('X'),
                                nonceStr: moment().format('x'),
                                package: 'prepay_id='+result.xml.prepay_id,
                                signType: "MD5"
                            }
                            temp.paySign = wx_sign(temp, pay_info[result.xml.appid].pay_key)
                            result.xml = temp
                        }
                        else {
                            res_body.successed = false
                            res_body.message = '支付失败'
                        }
                        if(res_body.message) {
                            res_body.datalist = result.xml
                            res.send(res_body);
                        }
                    });
                })
                    }
                    else {
                        res.send({
                            code: "applied",
                            successed: false,
                            message: '不能重复提交订单!'
                        });
                    }
        });
        
    }

    经常遇到的问题是会报签名错误问题,排查方法:

    1.排查微信支付申请的pay-key是否正确,或写成了appid、app-key;

    2.排查在上传MD5签名时是否传入了undefined的字段;

    3.如果都没问题,建议在微信商户管理后面中重新设置pay-key。

    统一下单结束后,小程序前端调用统一下单接口,开始微信支付:

    payNow: function (e) {
        let that = this;
        let data = {
          openid: app.globalData.openId,
          appid: app.globalData.app_id,
          body: this.data.applyGame.name + "测试",
          // attach: this.data.applyGame.id,//附加信息,暂时不添加
          total_fee: 1,
          notify_url: app.globalData.appUrl + 'sdk/wxpayvnotify', // 微信支付成功反馈通知接口
          where:{ // 不能重复提交订单条件
            status: orderStatus.pay,
          }
        };
        pay(data, (res) => {
          if (res.statusCode == 200) {
            if (res.data.successed == true) {
              let backobj = res.data.datalist;
    
              let timestamp = backobj.timeStamp;
              let nonceStr = backobj.nonceStr;
              let prepay_id = backobj.package;
              let signType = backobj.signType;
              let paySign = backobj.paySign;
              wx.requestPayment({
                'timeStamp': timestamp,
                'nonceStr': nonceStr,
                'package': prepay_id,
                'signType': signType,
                'paySign': paySign,
                'notify_url': app.globalData.appUrl + 'sdk/wxpayverify',
                success: function (res) {
                  wx.navigateTo({
                    url: "/pages/my-game/index",
                  })
                  wx.switchTab({
                    url: '/pages/my-game/index',
                  })
                },
                fail: function (res) {
                  console.log(res,'支付失败');
                  wx.showToast({
                    title: '支付失败!',
                    icon: 'none',
                  })
                  // wx.navigateTo({
                  //   url: "../pay/payfail/payfail",
                  // })
                },
              })
            } else {
              if (res.data.code === 'applied'){
                wx.showToast({
                  title: '已经报名',
                  icon: 'none',
                })
              }else{
                wx.showToast({
                  title: res.data.message,
                  icon: 'none',
                })
              }
              
            }
          }else{
            wx.showToast({
              title: '支付失败!',
              icon: 'none',
            })
          }
        })
      }

    支付完成。

    console.log(e,'s//s/');
    let that = this;
    // if (!this.data.payNowBottonUse) {//防止按钮重复点击
    // return;
    // }
    // this.setData({
    // payNowBottonUse: false
    // })

    let data = {
    openid: app.globalData.openId,
    appid: app.globalData.app_id,
    body: this.data.applyGame.name + "报名测试",
    // body: "pppddpdp",
    // detail: JSON.stringify(that.data.payOrdrInfoData.specific_project),//服务id
    // attach: this.data.applyGame.id,//附加信息,暂时不添加
    // //product_id: "002",//trade_type=NATIVE时(即扫码支付),此参数必传。
    total_fee: 1,
    notify_url: app.globalData.appUrl + 'sdk/wxpayvnotify',
    member_id: this.data.memberInfo.id,
    user_id: app.globalData.userId,
    game_id: this.data.applyGame.id,
    where:{ // 不能重复提交订单条件
    status: orderStatus.pay,
    gameId: this.data.applyGame.id,
    memberId: this.data.memberInfo.id
    }
    };
    pay(data, (res) => {
    if (res.statusCode == 200) {
    if (res.data.successed == true) {
    let backobj = res.data.datalist;
    console.log(backobj,'slslslslls');

    let timestamp = backobj.timeStamp;
    let nonceStr = backobj.nonceStr;
    let prepay_id = backobj.package;
    let signType = backobj.signType;
    let paySign = backobj.paySign;
    wx.requestPayment({
    'timeStamp': timestamp,
    'nonceStr': nonceStr,
    'package': prepay_id,
    'signType': signType,
    'paySign': paySign,
    'notify_url': app.globalData.appUrl + 'sdk/wxpayverify',
    success: function (res) {
    wx.navigateTo({
    url: "/pages/my-game/index",
    })
    wx.switchTab({
    url: '/pages/my-game/index',
    })
    },
    fail: function (res) {
    console.log(res,'支付失败');
    wx.showToast({
    title: '支付失败!',
    icon: 'none',
    })
    // wx.navigateTo({
    // url: "../pay/payfail/payfail",
    // })
    },
    })
    } else {
    if (res.data.code === 'applied'){
    wx.showToast({
    title: '该棋手已经报名',
    icon: 'none',
    })
    }else{
    wx.showToast({
    title: res.data.message,
    icon: 'none',
    })
    }
     
    }
    }else{
    wx.showToast({
    title: '支付失败!',
    icon: 'none',
    })
    }
    })
  • 相关阅读:
    2018级 面向对象程序设计 助教总结
    十二,时间序列趋势相似性度量方法的研究-DPM
    第十八周博客作业
    LSTM与BiLSTM
    基于自训练的半监督文本分类算法
    随机游走模型
    PMI点互信息
    Transductive Learning(直推式学习)
    TextCNN实验
    TextCNN
  • 原文地址:https://www.cnblogs.com/jlj9520/p/10689981.html
Copyright © 2011-2022 走看看