• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

nodejs+koa2微信app支付,小程序支付

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

企业付款到零钱文档;https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2

1,搞微信支付,先看流程图

https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3,先看流程图,看懂,再看微信支付api

2.调用统一下单接口

const router = new Router()
const uuid = require(\'uuid\')

router.post(\'wxpay\', async (ctx, next) => {
//1.根据orderCode查询订单状态和付款金额,此处省略

const order = { //参数一定要按照acil码(也就是a,b,c,d)顺序来写,或者你需要按照acil码自己排序,否则会在支付时报签名错误
appid: \'在微信中的应用appid,也在商户平台中\',
body: \'迪士尼\',
mch_id: \'微信平台中的商户编号\',
nonce_str: (uuid.v4()).replace(/-/g, \'\'),
notify_url: \'要回调的ulr,一定要是外网可访问的\',
out_trade_no: orderInfo[0].orderCode,
spbill_create_ip: ctx.request.ip.replace(/::ffff:/g, \'\'),
total_fee: 1, //先1分钱
trade_type: \'APP\' 
}
const objStr = objTostring(order)
const preSign = objStr + \'key=微信商户平台的key\'
order.sign = endeurl.md5(preSign).toUpperCase()
const xml = objToXml(order)

//调用统一下单接口

const data = await request.postAsync({
url: \'https://api.mch.weixin.qq.com/pay/unifiedorder\',
body: xml
})
const result = await parseStringAsync(data.body)

if (result.xml.result_code[0] == \'FAIL\') {
throw {
message: \'orderStatus wrong\'
}
}
//字符串必需按照顺序来
const paysign2 = {
appid: result.xml.appid[0],
noncestr: result.xml.nonce_str[0],
package: \'Sign=WXPay\',
partnerid: result.xml.mch_id[0],
prepayid: result.xml.prepay_id[0],
timestamp: parseInt(Date.now() / 1000).toString() //注意:时间必需为秒
}
const payPrestr = objTostring(paysign2) + \'key=微信商户平台的key\' //不知道的话,可以问老板
paysign2.sign = endeurl.md5(payPrestr).toUpperCase()

//二次签名,返回给app即可,由app端进行微信支付吊起
ctx.body = {
paysign2
}
})

3.工具类

const xml2js = require(\'xml2js\')
const Parser = new xml2js.Parser()
exports.parseStringAsync = xml => {
return new Promise((resolve, reject) => {
Parser.parseString(xml, (err, result) => {
if (err) {
reject(err)
} else {
resolve(result)
}
})
})
}
exports.objTostring = obj => {
var preSign = \'\';
for (let key in obj) {
preSign += `${key}=${obj[key]}&`
}
return preSign
}

exports.objToXml = obj => {
let xml = \'<xml>\'
for (let key in obj) {
xml += `<${key}>${obj[key]}</${key}>`
}
xml += \'</xml>\'
return xml
}

3.微信回调你在第二步是的notify_url值

router.post(\'wxNotify\', async (ctx, next) => {

//获取微信返回的参数值,查询订单状态

const data = ctx.params
var payQuery = {
appid: data.xml.appid[0],
mch_id: data.xml.mch_id[0],
nonce_str: data.xml.nonce_str[0],
out_trade_no: data.xml.out_trade_no[0],
transaction_id: data.xml.transaction_id[0]
}
let payQueryString = objTostring(payQuery) + \'key=微信商户平台的key\'
payQuery.sign = endeurl.md5(payQueryString).toUpperCase()
//查询订单是否支付成功
const data1 = await request.postAsync({
url: \'https://api.mch.weixin.qq.com/pay/orderquery\',
body: services.pay.objToXml(payQuery)
})

const result = await parseStringAsync(data1.body)

 if (result.xml.return_code[0] && result.xml.return_code[0] == \'SUCCESS\' && result.xml.trade_state[0] == \'SUCCESS\' ) {

//告诉微信,你收到支付结果通知了

const resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" +

"<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "
ctx.body = {
resXml
}

//从result中比较价格和你订单中的金额是否一致,,进行后台业务处理,此处省略

})

总结: 

1.参数一定要按照acil码(也就是a,b,c,d)顺序来写,或者你需要按照acil码自己排序(Object.keys(json)),否则会在支付时报签名错误

2.时间戳单位为秒,北京时间,别玩坏了,国外时间不能在国内不能玩

3.如果在支付时,报签名错误,先检查参数是否排序/参数值正确,如果还不行,请重置商户平台的key,再者不行,给微信支付技术支持发邮件,人家会在2小时内回复的

4.node微信app支付,就是以上代码两部分,剩下的就是app的事了

 

二、补充微信小程序支付统一下单,回调和app支付一致,不再重复

router.post(\'xcxPay\', async (ctx, next) => {
//1.根据orderCode查询订单状态和付款金额
const userId = ctx.user.userid
const orderInfo = await model.order.find({
\'orderStatus.status\': {
$in: [1, 9]
}
}, {
_id: 0,
orderCode: 1,
transCode: 1,
orderProducts: 1,
siteId: 1,
virtualProducts: 1,
CNYCharge: 1
})
if (!orderInfo || orderInfo.length < 1) {
throw {
status: 20001,
message: \'paying orderInfo not exists\',
router: ctx._url
}
log(222, \'订单状态错误\', orderInfo)
return
}
const userOpenId = await model.user.findOne({
_id: userId
}, {
_id: 0,
openIds: 1
})
if (!userOpenId || (userOpenId && !userOpenId.openIds && !userOpenId.openIds.wcx)) {
throw {
status: 20001,
message: \'wcx openid is not find !\',
router: ctx._url
}
return
}
let amount = orderInfo[0].CNYCharge

//字符串必需按照顺序来,比app支付参数稍有不同
const order = {
appid: \'小程序appid\',
body: \'糖葫芦\',
mch_id: \'商户号\',
nonce_str: (uuid.v4()).replace(/-/g, \'\'),
notify_url: `${config.apiUrl}/notify_url`,
openid: userOpenId && userOpenId.openIds && userOpenId.openIds.wcx || \'\', //小程序支付必须
out_trade_no: orderInfo[0].orderCode,
spbill_create_ip: ctx.request.ip.replace(/::ffff:/g, \'\'),
total_fee: Number(amount) * 100,
trade_type: \'JSAPI\' //小程序支付必须
}
const objStr = services.pay.objTostring(order)
const preSign = objStr + \'key=商户平台key\'
order.sign = endeurl.md5(preSign).toUpperCase()
const xml = services.pay.objToXml(order)
const data = await request.postAsync({
url: \'https://api.mch.weixin.qq.com/pay/unifiedorder\',
body: xml
})
const result = await services.pay.parseStringAsync(data.body)
if (result.xml.result_code[0] == \'FAIL\') {
throw {
message: \'orderStatus wrong\'
}
}

const paysign2 = {
appId: result.xml.appid[0],
nonceStr: result.xml.nonce_str[0],
package: `prepay_id=${result.xml.prepay_id[0]}`,
signType: \'MD5\',
timeStamp: parseInt(Date.now() / 1000).toString()
}
const payPrestr = services.pay.objTostring(paysign2) + \'key=商户平台key,同app支付\'
paysign2.paySign = md5(payPrestr).toUpperCase()
ctx.body = {
paysign2
}
})


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Java实现微信小程序支付(完整版)发布时间:2022-07-18
下一篇:
【微信小程序】调起微信支付完整demo发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap