1. 程式人生 > >React Native (IOS和Android) 支付寶和微信支付整合實戰(微信支付服務端篇)

React Native (IOS和Android) 支付寶和微信支付整合實戰(微信支付服務端篇)

序言React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。

微信支付——服務端整合

一、獲取你的APPID,MCH_ID以及配置的金鑰 key

微信沒有沙箱,所以在商戶平臺上,建立你的應用後,請妥善保管這三個重要的配置內容。 和支付寶類似,需要在服務端進行生籤操作,不同的是微信稍微步驟多一點,需要先獲取prepay,並且訪問和返回均為XML格式

 Android可按照官方文件 配置應用相關資訊


二、配置和編寫服務端程式碼

由於本分享以NodeJS為主,其他語言需要實現的步驟也是一樣的,可參考官方文件 具體的操作詳情以及需要注意的點如下:

1.按照微信統一下單的API,寫好訪問引數,並且進行生籤,和支付寶一樣,引數要按ASCII遞增,生籤後的簽名值要全部轉化為大寫,獲取prepay_id和相關內容。
2.注意所有進行簽名的變數名均為小寫,而簽名的sign值最後要轉化為大寫
3.注意返回至客戶端時,注意變數名的大小寫,詳情可參考react-native-wechat的github文件
// 配置相關變數
const APPID = ''          //你的微信應用APPID
const MCH_ID = ''         //你的商戶ID
const KEY = ''            //設定的金鑰key 
const NOTIFY_URL = 'http://192.168.1.45:3000/wechat/notify_url'     //設定你的回撥地址
// 根據訂單產生prepay的簽名
var prepaySign = function (order) {
    var ret = {
        appid: APPID,
        body: order.body,
        mch_id: MCH_ID,
        nonce_str: order.nonce_str,
        notify_url: NOTIFY_URL,
        out_trade_no: order.out_trade_no,
        spbill_create_ip: order.spbill_create_ip,
        total_fee: order.total_fee,
        trade_type: 'APP'
    };
    var string = helper.raw(ret);
    string = string + '&key=' + KEY;
    var crypto = require('crypto');
    var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex');
    return sign.toUpperCase();
}

//根據prepay的id,產生支付的簽名
var paySign = function (prepay) {
    var ret = {
        appid: APPID,
        noncestr: prepay.nonce_str,
        package: 'Sign=WXPay',
        partnerid: MCH_ID,
        prepayid: prepay.prepayid,
        timestamp: prepay.timestamp
    };
    var string = helper.raw(ret);
    string = string + '&key=' + KEY;
    var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex');
    return sign.toUpperCase();
}
// 訪問微信,根據訂單資訊,獲取prepay並且生成最後的支付訂單內容
var requestPrepay = function (order) {

    return new Promise((resolve, reject) => {
        var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        var formData = "<xml>";
        formData += "<appid>" + APPID + "</appid>"; //appid  
        formData += "<body>" + order.body + "</body>";
        formData += "<mch_id>" + MCH_ID + "</mch_id>"; //商戶號  
        formData += "<nonce_str>" + order.nonce_str + "</nonce_str>"; //隨機字串,不長於32位。  
        formData += "<notify_url>" + NOTIFY_URL + "</notify_url>";
        formData += "<out_trade_no>" + order.out_trade_no + "</out_trade_no>";
        formData += "<spbill_create_ip>" + order.spbill_create_ip + "</spbill_create_ip>";
        formData += "<total_fee>" + order.total_fee + "</total_fee>";
        formData += "<trade_type>APP</trade_type>";
        formData += "<sign>" + prepaySign(order) + "</sign>";
        formData += "</xml>";
        request({
            url: url,
            method: 'POST',
            body: formData
        }, function (err, response, body) {
            if (!err && response.statusCode == 200) {
                helper.getXMLNodeValue(body.toString("utf-8")).then((XML_RETURN) => {
                    var code = XML_RETURN.return_code[0];
                    var msg = XML_RETURN.return_msg[0];
                    if (code != 'SUCCESS' || msg != 'OK') {
                        deferred.reject({ message: XML_RETURN.return_msg[0] })
                        console.log(XML_RETURN)
                        return;
                    }

                    var prepay_id = XML_RETURN.prepay_id[0];

                    //簽名  
                    var _paySign = paySign(Object.assign({ prepayid: prepay_id }, order));
                    var args = {
                        appId: APPID,
                        partnerId: MCH_ID,
                        prepayId: prepay_id,
                        nonceStr: order.nonce_str,
                        timeStamp: order.timestamp,
                        package: 'Sign=WXPay',
                        sign: _paySign
                    };
                    resolve(args);
                })

            } else {
                reject(err)
                console.log(body);
            }
        });
    })

}

//產生訂單
wechat.post('/pay', function (req, res) {

    requestPrepay({
        body: '免費贈送IPhone X',
        out_trade_no: '453234533123',
        nonce_str: helper.createNonceStr(),
        spbill_create_ip: '192.168.1.45',  //一般可以從客戶端獲取使用者IP,
        total_fee: '1',                    //單位為分
        timestamp: helper.createTimeStamp()
    }).then((data) => {
        res.send(data)
    })
})

//回撥方法
wechat.post('/notify_url', function (req, res) {
    parser.parseString(req.body, function (err, result) {
        var wechatPayResult = result.xml

        console.log('wechat', wechatPayResult)
        var success = wechatPayResult.return_code[0] == 'SUCCESS'

        res.setHeader('content-type', 'application/xml')
        res.send('<xml><return_code><![CDATA[' + success ? 'SUCCESS' : 'FAIL' + ']]></return_code><return_msg><![CDATA[' + success ? 'OK' : 'FAIL' + ']]></return_msg></xml>')
    })

})


至此,微信服務端的配置已經完成了,相較於支付寶的服務端配置,稍微簡單一點,因為不需要產生公鑰私鑰,但是總體步驟是差不多的。
在這裡提醒開發者們,服務端生籤是一個非常重要的部分,如果這塊出現問題,客戶端是無法正常運作的,所以請仔細認真的核對程式碼,避免出錯,減少開發週期。
注意:以上程式碼請參考原始碼觀看,有部分方法整合至其他檔案。

鳴謝:我是一名來自盛安德的Shinetecher,感謝盛安德公司及同事們對IT技術的支援,分享和熱情,讓我有時間和動力完成此博文。

聯絡:歡迎各位朋友有任何問題和建議留言至此部落格下,或者新增本人微訊號:liyijia428 進行溝通交流學習