受欢迎的博客标签

  手机                        ->        云服务器     ->         微信官方支付服务器

(小程序云客户端) ->     (云函数)    ->           微信官方支付服务器

支付流程

step 1:用户点击支付按钮,获取支付金额,调用pay()函数

step 2:在pay()函数中将支付金额传递给云支付函数payment()建立订单

step 2:在pay()函数中调用云支付函数payment()成功后,会返回一系列的参数。

step 3:在pay()函数中利用利用调用云函数传回的结果参数,重新组合参数,

step 4: 在pay()函数中 传递组合后的参数给wx.requestPayment()函数,并调用 wx.requestPayment()函数发起真正的支付。

 

step 1:设计按钮

<!--miniprogram/pages/to-pay-order/index.wxml-->
<view class="container">
 <button bindtap='pay'>buy</button>  
</view>

step 2:点击按钮绑定的事件

// miniprogram/pages/to-pay-order/index.js

Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  

//本地发起下单请求并传送数据。这一步,在你的wxml中的某个元素
//中绑定事件<button bindtap='pay'>pay</button>。通过这个pay函数,
//触发云函数并传递一些数据
//https://blog.csdn.net/gf771115/article/details/100917779
  pay: function () {

    //需要上传给云函数的数据
    let uploadData = {
      //此次需要支付的金额,单位是分。例如¥1.80=180
      "total_fee": "180",
      //用户端的ip地址
      "spbill_create_ip": "123.123.123.123"
    }

    wx.cloud.callFunction({
      // 要调用的云函数名称
      name: 'payment',
      // 传递给云函数的event参数
      data: {
        x: 1,
        y: 2,
      }
    }).then(res => {
      console.log('调用云支付函数OK:'+res)

      var json = JSON.stringify(res);
      console.log('调用云函数[payment] 返回结果res:' + res + 'json:'+json)

    }).catch(err => {
      console.log('调用云支付函数fail: ' + err.errMsg)
    })

  }
   

})

step 3:在pay()函数中,调用支付函数

在pay()函数中,我们最终要调用wx.requestPayment()函数发起支付。但在调用wx.requestPayment()函数发起支付时,需要提供一些参数。后面所有的工作将围绕提供这些参数来进行。

见:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/payment/wx.requestPayment.html

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

支付函数原型如下:

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

package,paySign两个参数没有,这两个参数实际上需要由参数prepay_id组合而来。而prepay_id需要调用云函数云支付函数payment()获得。

假定云支付函数返回的结果如下:

<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx9*******]]></appid>
<mch_id><![CDATA[15****]]></mch_id>
<nonce_str><![CDATA[8Nqps2zzT3nsFx0U]]></nonce_str>
<sign><![CDATA[037AE8E124B96C0999****]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx17011444337695cbe988b3381***]]></prepay_id>
<trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

参数如下:

package=“prepay_id=wx2017033010242291fcfe0db70013231072”

paySign参数需要组合拼装,拼装规则如下:

1.五个字段参与签名(区分大小写):appId,nonceStr,package,signType,timeStamp

2.加上商户key

3.MD5加密

4.转换为大写

 var json = JSON.stringify(res);
      console.log('调用云函数[payment] 返回结果res:' + res + 'json:'+json)

      var prepay_id = res.result.split("<prepay_id><![CDATA[")[1].split("]]></prepay_id>")[0];
      var timeStamp = Math.round((Date.now() / 1000)).toString()
      var nonceStr = Math.random().toString(36).substr(2, 15)

      //五个字段参与签名(区分大小写):appId,nonceStr,package,signType,timeStamp
      var stringB =
        "appId=" + app.globalData.minappid
        + "&nonceStr=" + nonceStr
        + "&package=" + 'prepay_id=' + prepay_id
        + "&signType=MD5"
        + "&timeStamp=" + timeStamp
     
      var paySignTemp = stringB + "&key=" + app.globalData.mch_key
      console.log('step 2:调用wx.requestPayment发起支付签名原始字符串:' + paySignTemp)
      // 签名MD5加密
      var paySign = md5.md5(paySignTemp).toUpperCase()
      console.log('step 3:调用wx.requestPayment发起支付签名后:' + paySign)

 

示例:

var stringB=appId=wxd678efh567hg6787&nonceStr=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=wx2017033010242291fcfe0db70013231072&signType=MD5&timeStamp=1490840662
paySign = MD5(appId=wxd678efh567hg6787&nonceStr=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=wx2017033010242291fcfe0db70013231072&signType=MD5&timeStamp=1490840662&key=qazwsxedcrfvtgbyhnujmikolp111111) = 22D9B4E54AB1950F51E0649E8810ACD6

1.五个字段参与签名(区分大小写):appId,nonceStr,package,signType,timeStamp

 

 

下面的请求获取prepay_id参数。

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

准备一堆参数,然后发起调用,目的就是拿回prepay_id

 

1,小程序appid
2,云开发环境id
3,微信商户号
4,商户密匙

微信小程序微信支付官方流程图链接我简化的流程

 

 

 

 

step 3:客户端调用框架

选用Promise 风格调用

https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-client-api/functions/callFunction.html

 

pay: function () {

    wx.cloud.callFunction({
      // 要调用的云函数名称
      name: 'payment',
      // 传递给云函数的event参数
      data: {
        x: 1,
        y: 2,
      }
    }).then(res => {
      console.log('调用云支付函数OK:'+res)
    }).catch(err => {
      console.log('调用云支付函数fail: ' + err.errMsg)
    })

  }

step 4:新建云函数payment

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()

  return {
    event,
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID,
  }
}

先用硬编码来测试

// 云函数入口文件
const cloud = require('wx-server-sdk')
var request = require('request')

const crypto = require("crypto")


cloud.init()




// 云函数入口函数
exports.main = async(event, context) => {



  var json = JSON.stringify(event);
  console.log('云函数[payment]被调用 参数event:' + event + json)

  //准备参数如openid等信息
  const openid = event.userInfo.openId
  const appid = 'wx9b00e80b6***'
  const mch_id = '152*4***1'
  const key = '*****'
  const spbill_create_ip = "118.89.40.200" //终端IP
  const nonce_str = Math.random().toString(36).substr(2, 15)
  const total_fee = 100; // 支付金额,单位为分
  const body = "11"
  const attach = "订单"
  const notify_url = 'http://weixin.usdotnet.com/weixin'
  const trade_type = 'JSAPI'
  const timeStamp = parseInt(Date.now() / 1000) + ''
  const out_trade_no = "otn" + nonce_str + timeStamp;

  //第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序  见:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3
  let stringA = `appid=${appid}&body=${body}&mch_id=${mch_id}&nonce_str=${nonce_str}&notify_url=${notify_url}&openid=${openid}&out_trade_no=${out_trade_no}&spbill_create_ip=${spbill_create_ip}&total_fee=${total_fee}&trade_type=${trade_type}&key=${key}`
  //第二步:拼接API密钥:
  //stringA = stringA + '&key=${key}' //注:key为商户平台设置的密钥key

  console.log("====#1.对参数按照key=value的格式,并按照参数名ASCII字典序排序生成字符串:" + stringA + "=====================");

  //第三步:对stringA进行MD5运算,再将得到的字符串所有字符转换为大写。得到在云端服务器中生成的签名
  var sign = crypto.createHash('md5').update(stringA, 'utf8').digest('hex').toUpperCase()



  //第四步: 拼凑微信支付统一下单的参数,这个格式是要发给(post)微信支付服务器的内容
  let 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>" + out_trade_no + "</out_trade_no>"

  formData += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"

  formData += "<total_fee>" + total_fee + "</total_fee>"

  formData += "<trade_type>" + trade_type + "</trade_type>"


  formData += "<sign>" + sign + "</sign>"

  formData += "</xml>"


  console.log("=======================向微信服务器提交的xml:" + formData + "=====================");


  console.log("=======================本地计算的签名字符串:" + sign + "=====================");


  let options = {
    url: "https://api.mch.weixin.qq.com/pay/unifiedorder",
    method: "POST",
    timeout: 1000,
    body: formData,
  };

  const apireq = options => new Promise((resolve, reject) => request(options, (err, response, body) => {
    if (err)
     {
      reject(err);
      console.log("=======================支付云函数连接微信官方支付服务器失败:" + error + "=====================");
    } else 
    {
      resolve(body);
      console.log('支付云函数调用微信官方支付服务器返回的信息: ', body);
    }
  }));

  // 得到支付结果.格式为xml
  let  result = await apireq(options)

  return result;

  

 

}

 

成功返回的结果

<xml><return_code><![CDATA[SUCCESS]]></return_code>

<return_msg><![CDATA[OK]]></return_msg>

<appid><![CDATA[wx9*******]]></appid>

<mch_id><![CDATA[15****]]></mch_id>

<nonce_str><![CDATA[8Nqps2zzT3nsFx0U]]></nonce_str>

<sign><![CDATA[037AE8E124B96C0999****]]></sign>

<result_code><![CDATA[SUCCESS]]></result_code>

<prepay_id><![CDATA[wx17011444337695cbe988b3381***]]></prepay_id>

<trade_type><![CDATA[JSAPI]]></trade_type>

</xml>

失败的结果

<xml><return_code><![CDATA[FAIL]]></return_code>

<return_msg><![CDATA[签名错误]]></return_msg>

 

<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>

 

返回结果
"<xml><return_code><![CDATA[SUCCESS]]></return_code>\n<return_msg><![CDATA[OK]]></return_msg>\n<appid><![CDATA[wx9b00e80b6****]]></appid>\n<mch_id><![CDATA[15*****]]></mch_id>\n<nonce_str><![CDATA[5a7I0LWiPaAa1QJZ]]></nonce_str>\n<sign><![CDATA[7419DD696686A2ADD5B466D4FCDF6219]]></sign>\n<result_code><![CDATA[SUCCESS]]></result_code>\n<prepay_id><![CDATA[wx10212206059271b7365263ce1864643600]]></prepay_id>\n<trade_type><![CDATA[JSAPI]]></trade_type>\n</xml>"

 

微信小程序通过云函数进行微信支付

https://blog.csdn.net/gf771115/article/details/100917779

真机测试已通过未用第三方支付的代码

https://developers.weixin.qq.com/community/develop/doc/000620ec5acb482103b7bf41d51804

 

小程序云开发使用第三方库pay实现小程序支付功能(含源码)

https://developers.weixin.qq.com/community/develop/article/doc/000ceae09288489c0e9886e6c59c13

小程序云开发使用第三方库wx-js-utils实现小程序支付功能(含源码)

https://blog.csdn.net/weixin_34268310/article/details/91422026

小程序云开发使用第三方库wx.BaaS.pay实现小程序支付功能(含源码)

https://blog.csdn.net/chuizigun7053/article/details/100894595

小程序云开发使用第三方库tenpay实现小程序支付功能(含源码)

https://blog.csdn.net/qiushi_1990/article/details/99347580