微信小程序 + nodeJs(loopback) 實現支付

實現小程序的支付,首先須要去微信官網先了解一下微信小程序支付相關接口文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1php

微信支付首先須要調用微信的統一下單接口,返回微信支付接口須要數據。具體參數參考: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的字段;api

3.若是都沒問題,建議在微信商戶管理後面中從新設置pay-key。微信

統一下單結束後,小程序前端調用統一下單接口,開始微信支付:app

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',
})
}
})
相關文章
相關標籤/搜索