当前位置: 首页 > 后端技术 > Node.js

微信小程序从无到有接入支付

时间:2023-04-03 20:03:54 Node.js

最近一直在搞微信小程序的后台。这两天,我已经完成了支付相关的部分。有几个陷阱,我会在这里记录它们。首先申请激活支付,这里就不多说了。开启支付后,需要设置一个apikey,签名时使用。需要注意的是api只能在开头看到,所以需要保存。流程首先我们来梳理一下付款和下单的流程。下面是微信官方文档的流程图。在这里我将解释每个过程的作用。用户请求下订单。毫无疑问,订单是由商家自己的订单系统生成的。微信小程序请求下单付款。这里,请求付款的人必须是用户本人。如果用户未登录,则需要调用用户登录接口获取openid(注意:wx.getuserInfo不能直接获取openid,这是另外一个话题),如果已经登录,直接获取openid即可为服务器生成订单,这点不用怀疑。也是商家自己的订单系统。服务端调用统一下单接口生成预付交易,这是微信支付自身的必经流程。这部分需要更多的参数。需要注意。图片中没有提到的是签名。如果之前的不对,可以使用验证工具验证签名,检查是哪里出错了。这里的签名和下面小程序要求的签名是不一样的,注意不要搞混了。签名很简单:将数据带到请求统一订单的接口。如果签名正确,则返回预付款信息(prepay_id)。返回正确结果:收到正确结果后,需要对结果进行签名,返回给小程序,result为返回结果。只有下面列出的几个参数参与签名,其他的不需要。参考小程序的请求支付接口,发现接口参数齐全。如果一切正常,就可以付款了。实际'usestrict'constcrypto=require('crypto')constrequest=require('axios')constxml2js=require('xml2js')constparser=newxml2js.Parser()constbuilder=newxml2js.Builder()constqs=require('querystring')//生成签名函数getSign(data,apiKey){consttmpObj=Object.create(null)for(constkofObject.keys(data).sort())tmpObj[k]=data[k]constkey=decodeURIComponent(qs.stringify(tmpObj)+'&key='+apiKey)返回crypto.createHash('md5').update(key).digest('hex').toUpperCase()}classWXPay{constructor(options,apikey){this.options=optionsthis.apiKey=apikeythis.unifyOrderUrl='https://api.mch.weixin.qq.com/pay/unifiedorder'this.queryOrderUrl='https://api.mch.weixin.qq.com/pay/orderquery'this.sign=''}//请请求统计一次unifyOrder(obj){this.sign=getSign(Object.assign(obj,this.options),this.apiKey)const_wxData=builder.buildObject(Object.assign(obj,{sign:this.sign}))返回请求。post(this.unifyOrderUrl,_wxData,{headers:{'content-type':'text/xml'}}).then(result=>result.data).then(function(result){if(!result)返回Promise.reject(newError('数据不存在'))returnnewPromise(function(resolve,reject){parser.parseString(result,(err,_data)=>err?reject(err):resolve(_data.xml))})}).catch(err=>Promise.reject(err))}//获取微信支付配置WXPayConfig(data){returnthis.unifyOrder(data).then(result=>{if(!result)返回Promise.reject(newError('somethinggowrong'))for(letkeyinresult)result[key]=result[key][0]const_tmpData={appId:result.appid,timeStamp:(Date.now()/1000).toString(),nonceStr:result.nonce_str,package:'prepay_id='+result.prepay_id,signType:'MD5'}_tmpData.paySign=getSign(_tmpData,this.apiKey)返回_tmpData})。赶上(错误=>Promise.reject(错误))}//查询订单状态queryWXOrders(obj){this.sign=getSign(Object.assign(obj,this.options),this.apiKey)const_WXData=builder.buildObject(Object.assign(obj,{sign:this.sign}))returnrequest.post(this.queryOrderUrl,_WXData,{headers:{'content-type':'text/xml'}}).then(result=>result.data).then(function(result){if(!result)returnPromise.reject(newError('数据不存在'))returnnewPromise(function(resolve,reject){parser.parseString(result,(err,_data)=>err?reject(err):resolve(_data.xml))})}).catch(err=>Promise.reject(err))}}module.exports=WXPay以上代码可以直接使用,有空再补充