About using nodejs to build WeChat applet payment interface

Original link: https://blog.lipux.cn/archives/347/

foreword

Some time ago, when I developed a WeChat applet, I needed to use the payment function, so I went to see the official documents of WeChat payment. Good guy, WeChat officially only provides sdk of java, php and Go language. I can order PHP, but I am not very good at it. As a rookie front-end, Java will not let alone go. It happened that I just learned nodejs recently, and I was looking for someone to open source the nodejs version of the sdk. I wandered around in the WeChat developer community, but I didn’t expect it to exist, and I can take this opportunity to review nodejs again. . Here I will roughly record some of my usage methods.

payment process

1. Obtain the parameters required for payment from the back-end server 2. Use the obtained parameters to call the built-in payment api of the applet
3. Process business logic in the back-end interface of the callback

Initiate payment on WeChat applet

Looking at the official documents of the WeChat applet, we can find the api that WeChat applet initiates payment

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

It can be seen that we need to carry five parameters (timeStamp, nonceStr, package, signType,, paySign) to initiate payment normally.
So where can we get these parameters, which requires our nodejs to play.

payment module

Install using npm

 npm i wechatpay-node-v3

This package integrates the payment capabilities of H5 and App. For more detailed introduction, you can take a look at the official documentation of this package. Only the application in WeChat applet will be introduced here.

import dependency package

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

Among them, fs is a built-in module for file processing, and superagent is a module that initiates requests. If not, use npm to install it in advance, so I won’t introduce it here. Because we need to build an interface for front-end requests, we need to use the express server to build the framework, and we also need to use npm to install it in advance.

Create a payment instance

 const pay = new WxPay({ appid: '你的微信小程序appid', mchid: '商户号', publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公钥privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘钥});

Among them, the merchant account needs to be applied with a business license, and individuals cannot access WeChat payment.

After applying for the merchant account, you need to associate the merchant account on the WeChat applet management platform.

2022871606.png

Then you need to apply for public and private key certificates. For the specific application process, please refer to the official WeChat document below: Preparation before WeChat payment is connected

Then put the applied public key and private key certificate files in the same directory.

密钥文件

Get payment parameters

 async function payInfo(req,res){ const params = { description: 'Asnull的支付测试', // 订单描述out_trade_no: '2022080711111111', // 订单号,一般每次发起支付都要不一样,可使用随机数生成notify_url: 'https://pay.lipux.cn/notify_url', amount: { total: 1, // 支付金额,单位为分}, payer: { openid: 'drEc8QfY', // 微信小程序用户的openid,一般需要前端发送过来}, scene_info: { payer_client_ip: 'ip', // 支付者ip,这个不用理会也没有问题}, }; const result = await pay.transactions_jsapi(params); console.log(result); }

The callback url is the information of the payment result that the WeChat server will send to the callback url after the user successfully pays. Generally, we perform some business processing after the payment is successful in this callback url, and this callback url requires ssl certificate authentication. It is https, and parameters cannot be carried after the link. URL example: https://pay.lipux.cn/notify_url

Note: This callback url must be accessible from the public network, not a link to the local environment

Since pay.transactions_jsapi returns a promise object, we use the async and await functions to receive the result, where the result is the parameter required by the WeChat applet api to initiate payment.

The print result of result:

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

We can use the route listener res.send() function in express to send this result to the front end.

Then we parse the data on the front end and put it into the api of the WeChat applet wx.requestPayment to officially initiate the payment.

If nothing else, we have officially implemented the function of initiating payment in the WeChat applet.

handle business logic

As mentioned above, the callback url is an interface for processing business logic after successful payment.

When the payment is successful, the WeChat server will send a post request to our interface. The post request carries some parameters related to the payment result.

The payment result notification is to access the notification url set by the merchant in the POST method, and the notification data is transmitted through the request body (BODY) in JSON format. The notified data includes encrypted payment result details.

From the above words in the official WeChat payment document, we can see that the WeChat server sends us a piece of encrypted data, but don’t worry, the author of this module has solved it for us.

Let’s first take a look at what data the WeChat server sends us:

 { "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+wL6Uz71ZqNyawJ7BYGGh2aXwTu3DHMOullL/IoG3E1nRq1xQRmJsn0li4okegLRuTmlp3vvxZcNgHLOZSCmtdYcRYsZezB2wYdqsT5cCUmRgO8CdgctkGGQIOTjlgaKT8gogP7XUvw1bcFMAC4HqUJv2v28mfMTjFzhLNXXWCFDKJDWhCQg2ZTXw0pRJSYe/IiNBpuVsKX7DGahOyYly/Hn321fryiH7mpI5orC6Wb03Mc77hcnL9ALDV0jT8mrmYuB8pAMkxsFNcGcgnp5FrtKcA59CEYc4ccNU26wIiIszB0YIwvirvCEGys3eGStQaytFLvGw5qCmnZ6N5X3GPBOPEQXJa19CrVndWMjBm1PaeyJ/fgfN9mGrsChrToxDg==", "associated_data": "transaction", "nonce": "iOO0tvICpQFb" } }

We can see that some of the information is encrypted, and we need to decrypt the information in order to further process our business.

Decrypt callback result

We need to get the sent data through the req.body monitored by the callback route, that is, the json data in the above paragraph, and pass the corresponding ciphertext, associated_data, and nonce parameters into the following function:

 # key 用商户平台上设置的APIv3密钥【微信商户平台—>账户设置—>API安全—>设置APIv3密钥】,记为key; const result = pay.decipher_gcm(ciphertext, associated_data, nonce, key);

The key is an APIv3 key, and we need to apply for it separately. For the specific application process, please refer to the official document below: What is an APIv3 key? How to set it up? (qq.com)

After the decryption is successful, we get a new result result, which is printed as follows:

 { "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" } }

Among them, out_trade_no is the order number we set at the beginning. We can associate this order number with our users at the beginning, and then we can conduct business processing through the order number here, such as recharging members and recharging gold coins. and so on.

For the specific parameter description of the callback notification, please refer to the document: WeChat payment – developer documentation (qq.com)

At this point, we have completed the entire WeChat applet payment process. If there is no accident, you should be able to get the payment result normally.

The rest is your business logic!

full code

 /* * 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'); // 创建服务器实例const app = express(); // 配置解析表单数据的中间件app.use(express.urlencoded({ extended: false })) app.use(express.json()) // 监听端口app.listen(3031, () => { console.log('服务器启动成功!') }) // 创建支付实例const pay = new WxPay({ appid: '你的微信小程序appid', mchid: '商户号', publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公钥privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘钥}); // 定义一个获取支付参数路由(get请求) app.get('/pay', payInfo); // 拿到支付所需参数async function payInfo(req, res) { // 接收前端传过来的openid let openid = req.params.openid; const params = { description: 'Asnull的支付测试', // 订单描述out_trade_no: randomNumber(), // 订单号,一般每次发起支付都要不一样,可使用随机数生成notify_url: 'https://pay.lipux.cn/notify_url', amount: { total: 1, // 支付金额,单位为分}, payer: { openid: openid, // 微信小程序用户的openid,一般需要前端发送过来}, scene_info: { payer_client_ip: 'ip', // 支付者ip,这个不用理会也没有问题}, }; const result = await pay.transactions_jsapi(params); console.log(result); // 将结果响应给微信小程序前端res.send(result); } // 回调路由app.post('/notify_url', async(req, res) => { // 申请的APIv3 let key = '45c18fdfdgd45f5bc5321201dfdf453f'; let { ciphertext, associated_data, nonce } = req.body.resource; // 解密回调信息const result = pay.decipher_gcm(ciphertext, associated_data, nonce, key); // 拿到订单号let { out_trade_no } = result; if (result.trade_state == 'SUCCESS') { // 支付成功之后需要进行的业务逻辑} }) // 订单号生成函数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; }

at last

After the nodejs project is successfully deployed to the server, we only need to initiate a get request to https://domain/pay in the WeChat applet

After getting the data, call wx.requestPayment to initiate payment.

Finally, I wish you a happy ending!

refer to

https://www.npmjs.com/package/wechatpay-node-v3

This article is reproduced from: https://blog.lipux.cn/archives/347/
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment