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

企業付款到零錢文檔;https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2php

1,搞微信支付,先看流程圖node

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

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

//調用統一下單接口微信

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

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()async

//二次簽名,返回給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的事了

 

2、補充微信小程序支付統一下單,回調和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 }})

相關文章
相關標籤/搜索