定制软件关于使用nodejs搭建微信小程序支付接口

前言

定制软件前段时间在开发一个微定制软件信小程序的时候需要用定制软件到支付功能,定制软件我就去看了下的官方文档,好家伙,定制软件微信官方只提供了java、php还有Go语言的sdk。PHP我会点吧,定制软件但又不是很会,定制软件做为一个菜鸡前端,java定制软件也不会更别说go了。定制软件恰好我最近刚学了下nodejs,定制软件我就想找找有没有人做nodejs版的sdk开源,定制软件在微信开发者社区逛了定制软件逛没想到还真有,定制软件又可借此机会再复习一下nodejs也挺好的。定制软件在这里我将大致记录一定制软件下我的一些使用方法。

支付流程

一、定制软件向后端服务器获取支付所需参数
二、定制软件用获得的参数调用小程定制软件序内置的的支付api
三、定制软件在回调的后端接口中处定制软件理业务逻辑

定制软件在微信小程序发起支付

定制软件查看微信小程序的官方文档,我们可以查到微信小程序发起支付的api

wx.requestPayment({  timeStamp: '',  nonceStr: '',  package: '',  signType: 'MD5',  paySign: '',  success (res) { },  fail (res) { }})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以看到这里需要我们携带五个参数( timeStamp, nonceStr,package,signType,,paySign)才能正常发起支付。
那我们要在哪里才能获取到这些参数呢,这就需要我们的上场了。

支付模块

使用npm安装

npm i wechatpay-node-v3
  • 1

这个包集成了H5、App端的支付能力,更多详细的介绍可以去看一下这个包的官方文档,这里就只介绍在微信小程序的应用。

引入依赖包

const WxPay = require('wechatpay-node-v3');const fs = require('fs');const request = require('superagent');const express = require('express');
  • 1
  • 2
  • 3
  • 4

其中fs是一个文件处理的内置模块模块,superagent是一个发起请求的模块,若没有的话使用npm提前安装一下,这里就不多做介绍了。因为我们需要搭建一个可供前端请求的接口,我们就需要用到express框架,同样也是需要使用npm提前安装一下的。

创建支付实例

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

其中商户号需要凭营业执照才能申请,个人是无法接入微信支付的。

申请到商户号之后还需要在微信小程序的管理平台关联一下商户号。

然后还需要去申请公钥和私钥证书。具体的申请流程可看下方微信官方的文档:

之后把申请的公钥私钥证书文件放到同级目录下。

获取支付参数

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);   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

其中的回调url是当用户成功支付之后微信服务器就会向这个回调url发支付结果的信息,一般我们是在这个回调url里面进行一些支付成功之后的业务处理,而且这个回调url是需要ssl证书认证的也就是https,且在链接后面不能携带参数。url示例:https://pay.lipux.cn/notify_url

注意:这个回调url必须能公网访问的哦,不能是本地环境的链接

由于pay.transactions_jsapi返回的是一个promise对象,因此我们使用async和await函数进行接收结果,其中result就是微信小程序api发起支付所需要的参数。

result的打印结果:

{	appId: 'drEc8QfY',    timeStamp: '1609918952',    nonceStr: 'y8aw9vrmx8c',    package: 'prepay_id=wx0615423208772665709493edbb4b330000',    signType: 'RSA',    paySign: 'JnFXsT4VNzlcamtmgOHhziw7JqdnUS9qJ5W6vmAluk3Q2nska7rxYB4hvcl0BTFAB1PBEnHEhCsUbs5zKPEig==}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我们将这个结果使用express中的路由监听res.send()函数发送给前端就可以了。

然后我们就在前端解析这些数据,放到wx.requestPayment这个微信小程序的api中正式发起支付。

如果不出意外的话,在微信小程序发起支付这个功能我们就正式实现了

处理业务逻辑

上面提到了,回调url就是一个处理支付成功之后的业务逻辑的接口。

当支付成功之后,微信服务器会向我们这个接口发送一个post请求,这个post请求携带了一些有关支付结果的参数

支付结果通知是以POST 方法访问商户设置的通知url,通知的数据以JSON 格式通过请求主体(BODY)传输。通知的数据包括了加密的支付结果详情。

通过官方微信支付文档的上面这个话可知,微信服务器向我们发送的是一段加密的数据,但别担心,这个模块的作者都帮我们解决了。

我们先来看一下微信服务器都给我们发送了什么数据:

{ "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" }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们可以看到其中有段信息是被加密了,我们需要解密其中的信息才能进一步的进行我们业务处理。

解密回调结果

我们需要通过在回调的路由监听的req.body拿到发送的数据,即上面那一段的json数据,把对应的ciphertext, associated_data, nonce参数传入下面的函数:

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

其中的key是APIv3密钥,需要我们去另外申请,具体申请流程请看下面的官方文档:

解密成功之后我们就拿到一个新的结果result,打印出来如下:

{ "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" }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

其中的out_trade_no就是我们一开始设置的订单号,我们可以在一开始的时候就把这个订单号与我们的用户进行关联,然后在这里就可以通过订单号进行业务处理,比如说充值会员,充值金币等等的操作。

关于回调通知的具体参数说明可看文档:

到这里,我们已经完成了整个微信小程序支付的流程,不出意外的话你应该可以正常拿到支付的结果

剩下的就是你的业务逻辑了!

完整代码

/*  * 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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

最后

nodejs项目成功部署到服务器之后,我们只需要在微信小程序先对https://域名/pay 发起get请求

拿到数据后再调用wx.requestPayment即可发起支付。

最后,祝您玩的愉快!

参考

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发