|
用 thinkjs 封裝了個(gè)小程序支付的 Service 在這里記錄一下,順便梳理一下小程序支付的流程和思路。首先,先把官網(wǎng)的流程圖放上來,然后按照圖一步步的來。
第一步:用戶請求開發(fā)者后臺,發(fā)起下單請求
第二步:開發(fā)者查找一下數(shù)據(jù)庫或者緩存里是否有 openid 和 session_key
第三步:開發(fā)者服務(wù)器請求統(tǒng)一下單 API ,帶上要求的參數(shù): appid mch_id nonce_str sign body out_trade_no total_fee spbill_create_ip nonce_str 獲取隨機(jī)字符串:
test.js
/*
* 功能: 返回32位隨機(jī)字符串
* 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;
}
test.js
/*
* 功能:sign 參數(shù)簽名
* 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 =>{
//如果參數(shù)值為空,或者驗(yàn)證返回的 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;
}
得到這幾個(gè)參數(shù)就開始發(fā)起請求統(tǒng)一下單 API 了,這里需要注意的是,請求參數(shù)應(yīng)該以 xml 的形式傳送過去,這里借助一個(gè)工具 xml2js 把對象轉(zhuǎn)換為 xml,也可以把 xml 轉(zhuǎn)換為 對象、json。 安裝 xml2js npm i xml2js 使用 xml2js
test.js
const xml2js = require('xml2js');
//xml->json
//xml2js默認(rèn)會把子子節(jié)點(diǎn)的值變?yōu)橐粋€(gè)數(shù)組, explicitArray設(shè)置為false
var xmlParser = new xml2js.Parser({explicitArray : false, ignoreAttrs : true})
//json->xml
var jsonBuilder = new xml2js.Builder();
請求參數(shù)轉(zhuǎn)換為 xml
test.js
/*
* 功能:獲取統(tǒng)一下單 API 請求XML參數(shù)
* 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和網(wǎng)頁支付提交用戶端ip,Native支付填調(diào)用微信支付API的機(jī)器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;
}
然后就可以發(fā)起統(tǒng)一下單API請求了
test.js
/*
* 功能:調(diào)用統(tǒng)一下單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 轉(zhuǎn)換為 JSON
xmlParser.parseString(result,function(err, jsonData){
if(!err){
/* console.log(jsonData); */
data = jsonData;
}
});
return data;
}
第四步:當(dāng)請求成功時(shí) 判斷一下 return_code 和 result_code
第五步:拿上 prepay_id ,進(jìn)行再次簽名,然后返回給前端
test.js
/*
* 功能:統(tǒng)一下單接口返回 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'
}
//調(diào)用 統(tǒng)一下單 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;
}
//進(jìn)行再次簽名
let paySign = await this.makeSign(signString,config.key);
signString.paySign = paySign;
let { appid, signType, ...result } = signString;
// result 中不包括 appid 和 signType 返回給前端
return result;
}
第六步:用戶確認(rèn)支付后,小程序端調(diào)用支付接口,根據(jù)返回結(jié)果提示用戶
test.js
wx.requestPayment({
'timeStamp': '',
'nonceStr': '',//后端返回的隨機(jī)字符串
'package': '',//后端返回的
'signType': 'MD5',
'paySign': '',//后端返回的
'success':function(res){
},
'fail':function(res){
}
});
第七步:支付成功后,微信服務(wù)器會把支付結(jié)果返回給配置的 notify_url ,開發(fā)者根據(jù)支付結(jié)果,更新服務(wù)器的訂單狀態(tài)。 大體流程就是這,現(xiàn)在進(jìn)行到了 第四步 公司小程序 appid 還沒申請下來 商戶號 mch_id 也沒有,等過段時(shí)間繼續(xù)更新。(18/6/27) |