1. 程式人生 > 實用技巧 >微信小程式支付流程

微信小程式支付流程

首先,先把官網的流程圖放上來,然後按照圖一步步的來。

第一步:使用者請求開發者後臺,發起下單請求

  • 發起請求前在小程式端呼叫wx.checkSession()檢視session_key是否過期
    • 如果過期了 重新呼叫wx.login()返回session_keyopenid
    • 如果沒過期 繼續下一步操作,請求開發者後臺

第二步:開發者查詢一下資料庫或者快取裡是否有openidsession_key

  • 如果有生成訂單編號out_trade_no
  • 如果沒有返回錯誤訊息,缺少openidsession_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_coderesult_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,開發者根據支付結果,更新伺服器的訂單狀態。