溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用nodejs搭建微信小程序支付接口

發(fā)布時(shí)間:2022-12-28 09:10:05 來(lái)源:億速云 閱讀:191 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“如何使用nodejs搭建微信小程序支付接口”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“如何使用nodejs搭建微信小程序支付接口”文章能幫助大家解決問(wèn)題。

    支付流程

    一、向后端服務(wù)器獲取支付所需參數(shù)

    二、用獲得的參數(shù)調(diào)用小程序內(nèi)置的的支付api

    三、在回調(diào)的后端接口中處理業(yè)務(wù)邏輯

    在微信小程序發(fā)起支付

    查看微信小程序的官方文檔,我們可以查到微信小程序發(fā)起支付的api

    wx.requestPayment({
      timeStamp: '',
      nonceStr: '',
      package: '',
      signType: 'MD5',
      paySign: '',
      success (res) { },
      fail (res) { }
    })

    可以看到這里需要我們攜帶五個(gè)參數(shù)( timeStamp, nonceStr,package,signType,,paySign)才能正常發(fā)起支付。

    那我們要在哪里才能獲取到這些參數(shù)呢,這就需要我們的nodejs上場(chǎng)了。

    支付模塊

    使用npm安裝

    npm i wechatpay-node-v3

    這個(gè)包集成了H5、App端的支付能力,更多詳細(xì)的介紹可以去看一下這個(gè)包的官方文檔,這里就只介紹在微信小程序的應(yīng)用。

    引入依賴包

    const WxPay = require('wechatpay-node-v3');
    const fs = require('fs');
    const request = require('superagent');
    const express = require('express');

    其中fs是一個(gè)文件處理的內(nèi)置模塊模塊,superagent是一個(gè)發(fā)起請(qǐng)求的模塊,若沒(méi)有的話使用npm提前安裝一下,這里就不多做介紹了。因?yàn)槲覀冃枰罱ㄒ粋€(gè)可供前端請(qǐng)求的接口,我們就需要用到express服務(wù)器搭建框架,同樣也是需要使用npm提前安裝一下的。

    創(chuàng)建支付實(shí)例

    const pay = new WxPay({
      appid: '你的微信小程序appid',
      mchid: '商戶號(hào)',
      publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公鑰
      privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘鑰
    });

    其中商戶號(hào)需要憑營(yíng)業(yè)執(zhí)照才能申請(qǐng),個(gè)人是無(wú)法接入微信支付的。

    申請(qǐng)到商戶號(hào)之后還需要在微信小程序的管理平臺(tái)關(guān)聯(lián)一下商戶號(hào)。

    如何使用nodejs搭建微信小程序支付接口

    然后還需要去申請(qǐng)公鑰和私鑰證書(shū)。具體的申請(qǐng)流程可看下方微信官方的文檔:微信支付接入前準(zhǔn)備

    之后把申請(qǐng)的公鑰私鑰證書(shū)文件放到同級(jí)目錄下。

    如何使用nodejs搭建微信小程序支付接口

    獲取支付參數(shù)

    async function payInfo(req,res){
    	const params = {
            description: 'Asnull的支付測(cè)試', // 訂單描述
            out_trade_no: '2022080711111111', // 訂單號(hào),一般每次發(fā)起支付都要不一樣,可使用隨機(jī)數(shù)生成
            notify_url: 'https://pay.lipux.cn/notify_url', 
            amount: {
              total: 1, // 支付金額,單位為分
            },
            payer: {
              openid: 'drEc8QfY', // 微信小程序用戶的openid,一般需要前端發(fā)送過(guò)來(lái)
            },
            scene_info: {
              payer_client_ip: 'ip', // 支付者ip,這個(gè)不用理會(huì)也沒(méi)有問(wèn)題
            },
        };
          const result = await pay.transactions_jsapi(params);
          console.log(result);   
    }

    其中的回調(diào)url是當(dāng)用戶成功支付之后微信服務(wù)器就會(huì)向這個(gè)回調(diào)url發(fā)支付結(jié)果的信息,一般我們是在這個(gè)回調(diào)url里面進(jìn)行一些支付成功之后的業(yè)務(wù)處理,而且這個(gè)回調(diào)url是需要ssl證書(shū)認(rèn)證的也就是https,且在鏈接后面不能攜帶參數(shù)。url示例:https://pay.lipux.cn/notify_url

    注意:這個(gè)回調(diào)url必須能公網(wǎng)訪問(wèn)的哦,不能是本地環(huán)境的鏈接

    由于pay.transactions_jsapi返回的是一個(gè)promise對(duì)象,因此我們使用async和await函數(shù)進(jìn)行接收結(jié)果,其中result就是微信小程序api發(fā)起支付所需要的參數(shù)。

    result的打印結(jié)果:

    {
        appId: 'drEc8QfY',
        timeStamp: '1609918952',
        nonceStr: 'y8aw9vrmx8c',
        package: 'prepay_id=wx0615423208772665709493edbb4b330000',
        signType: 'RSA',
        paySign: 'JnFXsT4VNzlcamtmgOHhziw7JqdnUS9qJ5W6vmAluk3Q2nska7rxYB4hvcl0BTFAB1PBEnHEhCsUbs5zKPEig==
    }

    我們將這個(gè)結(jié)果使用express中的路由監(jiān)聽(tīng)res.send()函數(shù)發(fā)送給前端就可以了。

    然后我們就在前端解析這些數(shù)據(jù),放到wx.requestPayment這個(gè)微信小程序的api中正式發(fā)起支付。

    如果不出意外的話,在微信小程序發(fā)起支付這個(gè)功能我們就正式實(shí)現(xiàn)了

    處理業(yè)務(wù)邏輯

    上面提到了,回調(diào)url就是一個(gè)處理支付成功之后的業(yè)務(wù)邏輯的接口。

    當(dāng)支付成功之后,微信服務(wù)器會(huì)向我們這個(gè)接口發(fā)送一個(gè)post請(qǐng)求,這個(gè)post請(qǐng)求攜帶了一些有關(guān)支付結(jié)果的參數(shù)

    支付結(jié)果通知是以POST 方法訪問(wèn)商戶設(shè)置的通知url,通知的數(shù)據(jù)以JSON 格式通過(guò)請(qǐng)求主體(BODY)傳輸。通知的數(shù)據(jù)包括了加密的支付結(jié)果詳情。

    通過(guò)官方微信支付文檔的上面這個(gè)話可知,微信服務(wù)器向我們發(fā)送的是一段加密的數(shù)據(jù),但別擔(dān)心,這個(gè)模塊的作者都幫我們解決了。

    我們先來(lái)看一下微信服務(wù)器都給我們發(fā)送了什么數(shù)據(jù):

    {
     "id": "091541fc-6sca-55v8-ab24-653a9v313500",
     "create_time": "2022-08-07T16:39:06+08:00",
     "resource_type": "encrypt-resource",
     "event_type": "TRANSACTION.SUCCESS",
     "summary": "支付成功",
     "resource": {
      "original_type": "transaction",
      "algorithm": "AEAD_AES_256_GCM",
      "ciphertext": "tMqPpq3VCxwt56hU2gfsPDJfcfESQ/kzPNmi2xYF0KqMV9ChIWu+n5iVXSVqwgsU9gYSSXeThhp3jm8i9pcrTiOagMxEM/IbJ+MfnN7fkr8Jy2tWOg49N4wy3vB2Qd/nJvD+Jz8K6c4rF8MOasgN+XEriut23sd6EqGUY5zTaKQ+yZC7Q5R+Q6UXa4HlsvHH7+wL6Uz71ZqNyawJ7BYGGh3aXwTu3DHMOullL/IoG3E1nRq1xQRmJsn0li4okegLRuTmlp3vvxZcNgHLOZSCmtdYcRYsZezB2wYdqsT5cCUmRgO8CdgctkGGQIOTjlgaKT8gogP7XUvw1bcFMAC4HqUJv2v28mfMTjFzhLNXXWCFDKJDWhCQg2ZTXw0pRJSYe/IiNBpuVsKX7DGahOyYly/Hn321fryiH7mpI5orC6Wb03Mc77hcnL9ALDV0jT8mrmYuB8pAMkxsFNcGcgnp5FrtKcA59CEYc4ccNU26wIiIszB0YIwvirvCEGys3eGStQaytFLvGw5qCmnZ6N5X3GPBOPEQXJa19CrVndWMjBm1PaeyJ/fgfN9mGrsChrToxDg==",
      "associated_data": "transaction",
      "nonce": "iOO0tvICpQFb"
     }
    }

    我們可以看到其中有段信息是被加密了,我們需要解密其中的信息才能進(jìn)一步的進(jìn)行我們業(yè)務(wù)處理。

    解密回調(diào)結(jié)果

    我們需要通過(guò)在回調(diào)的路由監(jiān)聽(tīng)的req.body拿到發(fā)送的數(shù)據(jù),即上面那一段的json數(shù)據(jù),把對(duì)應(yīng)的ciphertext, associated_data, nonce參數(shù)傳入下面的函數(shù):

    # key 用商戶平臺(tái)上設(shè)置的APIv3密鑰【微信商戶平臺(tái)—>賬戶設(shè)置—>API安全—>設(shè)置APIv3密鑰】,記為key;
    const result = pay.decipher_gcm(ciphertext, associated_data, nonce, key);

    其中的key是APIv3密鑰,需要我們?nèi)チ硗馍暾?qǐng),具體申請(qǐng)流程請(qǐng)看下面的官方文檔:什么是APIv3密鑰?如何設(shè)置? (qq.com)

    解密成功之后我們就拿到一個(gè)新的結(jié)果result,打印出來(lái)如下:

    {
     "mchid": "3526524578",
     "appid": "wxc2n10fbb6065d4f0",
     "out_trade_no": "2022080711111111",
     "transaction_id": "8520001545602207282059123413",
     "trade_type": "JSAPI",
     "trade_state": "SUCCESS",
     "trade_state_desc": "支付成功",
     "bank_type": "OTHERS",
     "attach": "",
     "success_time": "2022-08-07T16:55:20+08:00",
     "payer": {
      "openid": "drEc8QfY"
     },
     "amount": {
      "total": 1,
      "payer_total": 1,
      "currency": "CNY",
      "payer_currency": "CNY"
     }
    }

    其中的out_trade_no就是我們一開(kāi)始設(shè)置的訂單號(hào),我們可以在一開(kāi)始的時(shí)候就把這個(gè)訂單號(hào)與我們的用戶進(jìn)行關(guān)聯(lián),然后在這里就可以通過(guò)訂單號(hào)進(jìn)行業(yè)務(wù)處理,比如說(shuō)充值會(huì)員,充值金幣等等的操作。

    關(guān)于回調(diào)通知的具體參數(shù)說(shuō)明可看文檔:微信支付-開(kāi)發(fā)者文檔 (qq.com)

    到這里,我們已經(jīng)完成了整個(gè)微信小程序支付的流程,不出意外的話你應(yīng)該可以正常拿到支付的結(jié)果

    剩下的就是你的業(yè)務(wù)邏輯了!

    完整代碼

    /* 
     * Created by Asnull.
     * Website:https://lipux.cn/
     */
    
    const WxPay = require('wechatpay-node-v3');
    const fs = require('fs');
    const request = require('superagent');
    const express = require('express');
    
    // 創(chuàng)建服務(wù)器實(shí)例
    const app = express();
    // 配置解析表單數(shù)據(jù)的中間件
    app.use(express.urlencoded({ extended: false }))
    app.use(express.json())
    // 監(jiān)聽(tīng)端口
    app.listen(3031, () => {
        console.log('服務(wù)器啟動(dòng)成功!')
    })
    
    // 創(chuàng)建支付實(shí)例
    const pay = new WxPay({
        appid: '你的微信小程序appid',
        mchid: '商戶號(hào)',
        publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公鑰
        privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘鑰
    });
    
    // 定義一個(gè)獲取支付參數(shù)路由(get請(qǐng)求)
    app.get('/pay', payInfo);
    
    // 拿到支付所需參數(shù)
    async function payInfo(req, res) {
        // 接收前端傳過(guò)來(lái)的openid
        let openid = req.params.openid;
        const params = {
            description: 'Asnull的支付測(cè)試', // 訂單描述
            out_trade_no: randomNumber(), // 訂單號(hào),一般每次發(fā)起支付都要不一樣,可使用隨機(jī)數(shù)生成
            notify_url: 'https://pay.lipux.cn/notify_url',
            amount: {
                total: 1, // 支付金額,單位為分
            },
            payer: {
                openid: openid, // 微信小程序用戶的openid,一般需要前端發(fā)送過(guò)來(lái)
            },
            scene_info: {
                payer_client_ip: 'ip', // 支付者ip,這個(gè)不用理會(huì)也沒(méi)有問(wèn)題
            },
        };
        const result = await pay.transactions_jsapi(params);
        console.log(result);
        // 將結(jié)果響應(yīng)給微信小程序前端
        res.send(result);
    }
    
    // 回調(diào)路由
    app.post('/notify_url', async(req, res) => {
        // 申請(qǐng)的APIv3
        let key = '45c18fdfdgd45f5bc5321201dfdf453f';
        let { ciphertext, associated_data, nonce } = req.body.resource;
        // 解密回調(diào)信息
        const result = pay.decipher_gcm(ciphertext, associated_data, nonce, key);
        // 拿到訂單號(hào)
        let { out_trade_no } = result;
        if (result.trade_state == 'SUCCESS') {
            // 支付成功之后需要進(jìn)行的業(yè)務(wù)邏輯
        }
    })
    
    // 訂單號(hào)生成函數(shù)
    function randomNumber() {
        const now = new Date()
        let month = now.getMonth() + 1
        let day = now.getDate()
        let hour = now.getHours()
        let minutes = now.getMinutes()
        let seconds = now.getSeconds()
        month = month < 10 ? "0" + month : month;
        day = day < 10 ? "0" + day : day;
        hour = hour < 10 ? "0" + hour : hour;
        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;
        let orderCode = now.getFullYear().toString() + month.toString() + day + hour + minutes + seconds + (Math.round(Math.random() * 1000000)).toString();
        return orderCode;
    }

    關(guān)于“如何使用nodejs搭建微信小程序支付接口”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI