手机 -> 云服务器 -> 微信官方支付服务器
(小程序云客户端) -> (云函数) -> 微信官方支付服务器
支付流程
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}¬ify_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