程序设计 Opencv mongoose interface emacs combobox 后台ui模板 网络营销视频 mysql降序 matlab注释一段 arraylist删除指定元素 mser算法 less比较级 js控制台打印 matlab读入图片 python循环 配置python环境 java简介 java编程基础 java接口怎么写 java终止线程 java判断语句 java写入txt java定义字符串 linux云服务器 脚本之家 java电子书下载 vue上传文件 迅雷免费会员号共享 心理学与生活pdf 银头鲑鱼 自动回复机器人 cdr字体变形 神牧属性 苹果手机耳机没声音 excel后缀 非凡资源搜索器 手机电池容量怎么看 易语言tv 机械键盘光轴
当前位置: 首页 > 学习教程  > 

Nodejs后端实现微信小程序支付

2020/10/16 17:59:54 文章标签: nodejs后端开发

Nodejs后端实现微信小程序支付一、前言二、微信小程序支付流程三、工具类四、微信支付统一下单接口解析五、小程序调用微信支付六、总结一、前言 前端时间在做微信小程序后端的时候,小程序中用到了微信支付的功能,后端需要接入微信支付的接口&#xff0…

Nodejs后端实现微信小程序支付

    • 一、前言
    • 二、微信小程序支付流程
    • 三、工具类
    • 四、微信支付统一下单接口解析
    • 五、小程序调用微信支付
    • 六、总结

一、前言

前端时间在做微信小程序后端的时候,小程序中用到了微信支付的功能,后端需要接入微信支付的接口,实现小程序的支付功能。第一次接触支付相关的内容,在此写篇文章记录一下。

二、微信小程序支付流程

首先引用微信官方的小程序支付流程图:【微信官方支付API文档】
在这里插入图片描述
微信官方给出的支付流程包含了微信支付需要的各部分内容,比较全面,但是根据不同的项目需求,所需要的开发流程是不同的,有些步骤根据项目是可以做适当的调整的。但是微信支付的整体套路是一样的,

首先小程序端将商品等信息发给后端,后端在本地生成一个订单,并将订单信息返回给小程序,小程序确认订单信息后,发起支付请求,后端收到请求后,将参数进行签名处理,然后调用微信支付的统一下单接口,将处理后的数据发送给微信支付后台,微信后台将预支付单信息返回给后端,后端进行二次签名,将处理后的数据返回给小程序,小程序根据返回的数据调起微信支付工具,用户完成支付之后,直接将数据发送给微信支付后台,微信支付后台将支付结果返回给小程序,同时微信支付后台还会通过异步的方式将支付结果发送给后端,后端将支付结果通知进行处理,便于小程序进行支付结果查询的操作。这样微信小程序的支付就结束了。

注意:要使用微信支付的功能,首先要有小程序的ID和密钥,其次需要用户的微信商户ID和密钥,这样才能成功开通微信支付功能。

三、工具类

1.数据签名算法
微信支付过程发送的数据用到了签名的加密形式,【微信官方签名算法】。
1)将需要发送的参数按照参数名ASCII码从小到大排序(字典序),在使用URL键值对的形式(key1=value1&key2=value2…)将参数拼接成字符串stringA。
参考代码:

raw = (args: any) => {
        let keys: any = Object.keys(args);
        keys = keys.sort();
        const results: Array<string> = [];
        keys.forEach((key: string) => {
            results.push(`${key}=${args[key]}`)
        });

        return results.join("&");
    }

2)在stringA的末尾拼接上Key值得到stringSignTemp字符串。

stringSignTemp = stringA + "&key=" + key;

3)将得到的字符串进行MD5运算,再将结果全部转换为大写,得到最终的sign值signValue。(这里后端使用”crypto-js”包来进行MD5运算)

cryptoJS.MD5(str).toString().toUpperCase();

完整签名方法:

paySignApp_1 = (appid, body, mch_id, nonce_str, notify_url, out_trade_no, spbill_create_ip, total_fee, trade_type, mchkey) => {
        const ret: any = {
            appid,
            mch_id,
            nonce_str,
            body,
            notify_url,
            out_trade_no,
            spbill_create_ip,
            total_fee,
            trade_type
        };
        let str: any = this.raw(ret);
        const key = mchkey;
        str = str + "&key=" + key;
        return cryptoJS.MD5(str).toString().toUpperCase();
    }

2.获取随机字符串
传递的参数中需要一个16位的随机字符串

createNonceStr = () => {
    return Math.random().toString(36).substr(2, 15);
}

3.获取时间戳
传递的参数中需要一个时间戳字符串

createTimeStamp = () => {
    return parseInt((new Date().getTime() / 1000).toString()) + "";
}

4.金额转换
微信支付中的参数支付金额的单位是分,参数值不能带小数,所以需要对参数进行金额处理

getMoney = (money) => {
    return parseFloat(money) * 100;
}

四、微信支付统一下单接口解析

微信支付的关键点就在统一下单接口的使用。参数的详情介绍请参考【微信支付统一下单接口】
1.参数定义
小程序和商户数据配置:

private appId = "小程序ID";
private appSecret = "小程序密钥";
private mchId = "商户ID";
private mchKey = "商户密钥";
private notifyUrl = "自己后端定义的支付结果通知获取地址";

前端传递的参数配置:(注意:openid是前端通过微信登录获取的用户标识ID,是用户唯一的,这里由前端获取并发送给后端。wxpay是自己写的工具类的脚本,里面包含了签名等方法)

const orderCode = req.body.orderCode; //订单号
const money = req.body.money;
const openid = req.body.openid;
const mchId = this.mchId;
const nonceStr = this.wxpay.createNonceStr();
const timestamp = this.wxpay.createTimeStamp();
const body = "微信支付测试";
const outTradeNo = orderCode;
const totalFee = this.wxpay.getMoney(money);
const spbillCreateIp = req.connection.remoteAddress;
const notifyUrl = this.notifyUrl ;
const tradeType = "JSAPI";
const sign = this.wxpay.paySign_1(this.appId, body, mchId, nonceStr, notifyUrl, openid, outTradeNo, spbillCreateIp, totalFee, tradeType, this.mchKey);

2.将参数封装成XML数据格式 (注意:直接插入数据会出现错误,这里需要对XML数据进行转义,或者使用下面的方式传值<![CDATA[data]]>)

const formData = `
        <xml>
        <appid><![CDATA[${this.appId}]]></appid>
        <body><![CDATA[${body}]]></body>
        <mch_id><![CDATA[${mchId}]]></mch_id>
        <nonce_str><![CDATA[${nonceStr}]]></nonce_str>
        <notify_url><![CDATA[${notifyUrl}]]></notify_url>
        <openid><![CDATA[${openid}]]></openid>
        <out_trade_no><![CDATA[${outTradeNo}]]></out_trade_no>
        <spbill_create_ip><![CDATA[${spbillCreateIp}]]></spbill_create_ip>
        <total_fee><![CDATA[${totalFee}]]></total_fee>
        <trade_type><![CDATA[${tradeType}]]></trade_type>
        <sign><![CDATA[${sign}]]></sign>
        </xml>
        `;

3.调用统一下单接口 (注意:这里使用“request”包来发送请求。微信支付后台返回的数据是XML格式的,这里使用“xmlreader”包来读取数据内容。)

const url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
request({ url: url, method: "POST", body: formData }, (err, response, body) => {
	if (!err && response.statusCode == 200) {
		xmlreader.read(body.toString("utf-8"), (error, response) => {
			if (null !== error) {
				return;
			}
			if (response.xml.return_code.text() === "SUCCESS") {
				const prepayId = response.xml.prepay_id.text();

				const packages = "prepay_id=" + prepayId;
				const signType = "MD5";
				const minisign = this.wxpay.paySign_2(this.appId, nonceStr, packages, signType, timestamp, this.mchKey);

				const data = {
					"appId": this.appId,
					"partnerId": mchId,
                    "prepayId": prepayId,
                    "nonceStr": nonceStr,
                    "timeStamp": timestamp,
                    "package": "Sign=WXPay",
                    "paySign": minisign
                };
                res.send(data);
			}
			else {
				res.send(response.xml.return_msg.text());
			}
		}
	}
}

微信后台统一下单接口返回数据后,对数据进行二次签名处理,将处理后的数据再返回给小程序使用。

这样微信支付后端的流程就结束了。

五、小程序调用微信支付

小程序端我没有参与开发,这里简单说一下小程序端的调用流程。小程序端调用微信支付比较简单,主要是调用wx.requestPayment()来调起微信支付工具。
1.封装数据调用后端的统一下单接口

2.根据后端返回的数据调用wx.requestPayment(),直接把数据发送给微信支付后台。

3.执行requestPayment的回调方法,根据微信支付后台返回的支付结果来处理不同的实际逻辑。
这样微信小程序的支付流程就结束了。

六、总结

当时在进行开发的时候遇到了很多问题,由于是第一次开发支付相关的内容,踩了很多坑,而且微信官方给的开发文档实在是一言难尽,无力吐槽。微信支付中还有对微信支付结果异步发送给后端的处理,以及退款操作,这两点还有很多坑,后面会写文章来说一下这两个操作该如何处理。


本文链接: http://www.dtmao.cc/news_show_300257.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?