首先,先把官网的流程图放上来,然后按照图一步步的来。
第一步:用户请求开发者后台,发起下单请求
- 发起请求前在小程序端调用
wx.checkSession()
查看session_key
是否过期- 如果过期了 重新调用
wx.login()
返回session_key
和openid
- 如果没过期 继续下一步操作,请求开发者后台
- 如果过期了 重新调用
第二步:开发者查找一下数据库或者缓存里是否有 openid
和 session_key
- 如果有生成订单编号
out_trade_no
- 如果没有返回错误消息,缺少
openid
、session_key
第三步:开发者服务器请求统一下单 API
,带上要求的参数:
appid
mch_id
nonce_str
sign
body
out_trade_no
total_fee
spbill_create_ip
nonce_str
获取随机字符串:
test.js
js
/* * 功能: 返回32位随机字符串 * create by tiankai on 2018-06-25 15:39 */ getNonceStr(){ let char = \'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\'; let len = 32; let result = \'\'; for(let i = 0; i < len; i++){ let randomNum = Math.floor(Math.random()*char.length); result += char[randomNum]; } return result; }
sign
参数签名, 第二个tab(js)是调用函数的方法, key
为商户平台设置的密钥 key
test.js
- js
- js
/* * 功能:sign 参数签名 * create by tiankai on 2018-06-26 12:00 */ async makeSign(params, key){ // 生成签名 sign let strOrderArr = Object.keys(params).sort(); let stringA = ""; strOrderArr.map(val =>{ //如果参数值为空,或者验证返回的 sign 不参与签名 if( think.isNullOrUndefined(params[val]) || val === \'sign\' || params[val].length === 0 ) return; stringA += val + "=" + params[val] + "&"; }); let stringSignTemp = stringA + "key=" + key; let sign = think.md5(stringSignTemp).toUpperCase(); return sign; }
得到这几个参数就开始发起请求统一下单 API 了,这里需要注意的是,请求参数应该以 xml
的形式传送过去,这里借助一个工具 xml2js
把对象转换为 xml,也可以把 xml 转换为 对象、json。
安装 xml2js
npm i xml2js
使用 xml2js
test.js
js
const xml2js = require(\'xml2js\'); //xml->json //xml2js默认会把子子节点的值变为一个数组, explicitArray设置为false var xmlParser = new xml2js.Parser({explicitArray : false, ignoreAttrs : true}) //json->xml var jsonBuilder = new xml2js.Builder();
请求参数转换为 xml
test.js
js
/* * 功能:获取统一下单 API 请求XML参数 * create by tiankai on 2018-06-25 15:23 */ async getUnifiedOrderParams(){ let signString = { appid: config.appid, mch_id: config.mchid, nonce_str: await this.getNonceStr(), body: \'短信平台-短信套餐购买\', out_trade_no: \'20180926125346\',//订单号 total_fee: 88,//订单金额 //APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP //需要自行获取,这里只是为了测试直接写上了 spbill_create_ip: \'123.12.12.123\', notify_url: config.notify_url, trade_type: \'JSAPI\', openid: await think.cache(\'openId\') } let sign = await this.makeSign(signString,config.key); signString.sign = sign; /* console.log("--------------------------"); * console.log(sign); * console.log("--------------------------"); */ let xml = await jsonBuilder.buildObject(signString); /* console.log(xml); */ return xml; }
然后就可以发起统一下单API请求了
test.js
js
/* * 功能:调用统一下单API接口 * create by tiankai on 2018-06-26 11:01 */ async unifiedOrder(){ let xmlParams = await this.getUnifiedOrderParams(); let unifiedOrderUrl = config.unifiedOrderUrl; let opt = { method: "POST", mode: \'cors\', headers: { \'content-type\': \'text/xml\' }, body: xmlParams } let res = await this.fetch(unifiedOrderUrl, opt); //这里微信返回的也是 xml let result = await res.text(); let data = null; // 微信返回的 XML 转换为 JSON xmlParser.parseString(result,function(err, jsonData){ if(!err){ /* console.log(jsonData); */ data = jsonData; } }); return data; }
第四步:当请求成功时 判断一下 return_code
和 result_code
- 如果它们都等于
SUCCESS
的时候,微信会把我们需要的预支付订单信息prepay_id
返回来, - 否则返回
return_msg
给前端 展示具体错误
第五步:拿上 prepay_id
,进行再次签名,然后返回给前端
test.js
js
/* * 功能:统一下单接口返回 prepay_id 再次签名 返回给前端 * create by tiankai on 2018-06-26 15:45 */ async payParams(){ let signString = { appid: config.appid, timeStamp: +new Date(), nonce_str: await this.getNonceStr(), package: null, signType: \'MD5\' } //调用 统一下单 API let jsonData = await this.unifiedOrder(); if(think.isNullOrUndefined(jsonData) && jsonData.xml.return_code === \'SUCCESS\' && jsonData.xml.result_code === \'SUCCESS\' ){ signString.package = \'perpay_id=\'+jsonData.xml.perpay_id }else{ return jsonData.xml.return_msg; } //进行再次签名 let paySign = await this.makeSign(signString,config.key); signString.paySign = paySign; let { appid, signType, ...result } = signString; // result 中不包括 appid 和 signType 返回给前端 return result; }
第六步:用户确认支付后,小程序端调用支付接口,根据返回结果提示用户
test.js
js
wx.requestPayment({ \'timeStamp\': \'\', \'nonceStr\': \'\',//后端返回的随机字符串 \'package\': \'\',//后端返回的 \'signType\': \'MD5\', \'paySign\': \'\',//后端返回的 \'success\':function(res){ }, \'fail\':function(res){ } });
第七步:支付成功后,微信服务器会把支付结果返回给配置的 notify_url
,开发者根据支付结果,更新服务器的订单状态。
请发表评论