微信小程序支付二 支付开发

注意:以下测试用例的后端语言选取的是node.js,框架采用的是express。希望读者在看这篇博客前已经了解了相关知识,如果你想学习node.js,建议你上菜鸟教程。框架的话可以看下面这个链接,个人感觉讲解得很详细了。https://blog.csdn.net/qq_empire/article/details/80933726

开发步骤:
1.小程序内调用登录接口,拿到code,然后发送给后端,后端获取到openid(用户唯一标识符)。
2.获取到openid后,商户server调用支付统一下单。
3.商户server调用再次签名。
4.支付完成。

前端
wxml

<button bindtap='payMoney'>支付</button>

js

Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },
  payMoney: function (e) {
    wx.login({
      success: res => {
        console.log(res.code)
        var that = this;
        wx.request({
          url: 'http://127.0.0.1:3030/get_openid?code=' + res.code + '&money=' + 0.01,
          success: function (res) {

            console.log(res.data, '统一下单接口返回信息')

            wx.requestPayment({
              timeStamp: res.data.timeStamp ,  //时间搓
              nonceStr: res.data.nonceStr, //随机字符串
              package: 'prepay_id='+res.data.package,  //prepay_id
              signType: 'MD5', //签名算法
              paySign: res.data.paySign,  //签名
              success(res) {
                console.log(res, '微信支付成功!!!')
              },
              fail(error){
                console.log(error, '微信支付失败!!!')
              }

          })
        }
      })
    }
    })
  },
})

后端

var express = require('express');
var router = express.Router();
var request = require('request')	//引入request请求模块(这三个模块需要重新下载一次,配置到服务器上时)
var md5 = require('md5-node')	//引入md5加密模块
var xml2js = require('xml2js');	//引入xml解析模块

/* GET home page. */
router.get('/', function(req, res, next) {
	let query = req.query;
	console.log(query,'获取请求参数')	
	let out_trade_no = new Date().getTime()+'_chaoxian';	//商户订单号
	let nonce_str = randomStr();
	let openid = null;
	let total_fee = Number(query.money)*100;
	let appid = '';	//自己的小程序appid
	let mch_id ='';	//自己的商户号id
	console.log("第一次签名的信息:\n appid:"+appid);
	console.log("mch_id:"+mch_id);
	console.log("nonce_str:"+nonce_str);
	console.log("total_fee:"+total_fee);
	console.log("out_trade_no:"+out_trade_no);
	getOpenid(query.code,appid).then(function(res1){
		openid = res1;//执行完同步函数之后将获取到的openid赋值
		console.log("获取到openid:"+openid)	
		let sign = createSign({	//签名
			appid: appid,//小程序的appid
			body: 'test',//描述
			mch_id: mch_id,//商户号
			nonce_str: nonce_str,//32位随机字符串
			notify_url: 'https://www.chaoxian2018.cn:3030/',//随便一个可以访问的https都行,记住不能带参数
			openid: openid,
			out_trade_no: out_trade_no,
			spbill_create_ip: '127.0.0.1',//可以写固定的ip,这里就用本地的,你可以更改为获取用户ip也行
			total_fee: total_fee,
			trade_type: 'JSAPI'
		});
		console.log("第一次签名之后的sign:"+sign);

let reqUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//统一下单请求的url
		let  formData = "<xml>";
							formData += "<appid>"+appid+"</appid>"; //appid 
							formData += "<mch_id>" +mch_id+ "</mch_id>"; //商户号 
							formData += "<nonce_str>" +nonce_str+ "</nonce_str>"; //随机字符串,不长于32位。
							formData += "<sign>" +sign+ "</sign>";
							formData += "<body>test</body>";
							formData += "<out_trade_no>" +out_trade_no+ "</out_trade_no>";
							formData += "<total_fee>" +total_fee+ "</total_fee>";
							formData += "<spbill_create_ip>127.0.0.1</spbill_create_ip>";
						    formData += "<notify_url>https://www.chaoxian2018.cn:3030/</notify_url>";
						    formData += "<trade_type>JSAPI</trade_type>";
						    formData += "<openid>"+openid+"</openid>";
							formData += "</xml>";

request({
		    url: reqUrl,
		    method: "POST",
		    json: true,
		    headers: {
		        "content-type": "application/json",
		    },
		    body: formData
		}, function(error, response, body) {
		    if (!error && response.statusCode == 200) {
		        console.log(body,'统一下单接口返回的数据') // 请求成功的处理逻辑
		        xml2js.parseString(body,function(error,result){
		        	console.log(JSON.stringify(result),'xml解析成json字符串')
		        	let reData = result.xml;
		        	let timestamp=timest();
		        	let noncestr=reData.nonce_str[0];
		        	let package=reData.prepay_id[0];
		        	let signtype='MD5';
		        	console.log("进行二次签名需要的参数:\n appid:"+appid);
		        	console.log("nonceStr:"+noncestr);
		        	console.log("package:"+package);
		        	console.log("signType:"+signtype);
		        	console.log("timeStamp:"+timestamp);
		        	//二次签名
		        	let paySign=creatPaySign({
		        		appId:appid,
		        		noncestr:noncestr,
		        		package:package,
		        		signtype: signtype,
		        		timestamp: timestamp,
		        	});
		        	console.log("第二次签名之后的sign:"+paySign);
		        	
		        	
		        	let responseData = {
		        		timeStamp: timestamp,
		        		nonceStr: noncestr,
		        		package: package,
		        		paySign: paySign,
		        	}
		        	
		        	res.end(JSON.stringify(responseData))
 
		        })
		    }
		}); 
		
	});
	
});

function getOpenid(code,appid){	//发起请求获取用户的openID
	return new Promise(function(resolve,reject){	
		request('https://api.weixin.qq.com/sns/jscode2session?appid='+appid+'&secret='+
'&js_code='+code+'&grant_type=authorization_code',function(error,response,body){
			if(!error && response.statusCode == 200){
				var bodyJson = JSON.parse(body)
				//console.log(bodyJson,'获取openID返回信息')
				resolve(bodyJson.openid);
			}
		})
	})
}

function createSign(obj){	//签名算法(把所有的非空的参数,按字典顺序组合起来+key,然后md5加密,再把加密结果都转成大写的即可)
	var stringA = 'appid='+obj.appid+'&body='+obj.body+'&mch_id='+obj.mch_id+'&nonce_str='+obj.nonce_str+'&notify_url='+obj.notify_url+'&openid='+obj.openid+'&out_trade_no='+obj.out_trade_no+'&spbill_create_ip='+obj.spbill_create_ip+'&total_fee='+obj.total_fee+'&trade_type='+obj.trade_type;
	
	
	var stringSignTemp = stringA+'&key=';//这里的key需要改成自己的key
	console.log("第一次加密前的字符串:"+stringSignTemp)
		stringSignTemp = md5(stringSignTemp);
	var signValue = stringSignTemp.toUpperCase();
	return signValue
}

function creatPaySign(obj){
//二次签名
	var string_paysign="appId="+obj.appId+'&nonceStr='+obj.noncestr+'&package=prepay_id='+obj.package+
	'&signType='+obj.signtype+'&timeStamp='+timest();
	var pay_link=string_paysign+'&key=';//这里的key需要改成自己的key
	console.log("第二次加密前的字符串:"+pay_link)
		pay_link= md5(pay_link);
	var signResult=pay_link.toUpperCase();
	return signResult;
	
}

function randomStr(){	//产生一个随机字符串	
    var str = "";    
    var arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
 	
 	for(var i=1;i<=32;i++){
 		var random = Math.floor(Math.random()*arr.length);
 		str += arr[random];
 	}
		
    return str;
}
//从1970年开始的毫秒数然后截取10位变成 从1970年开始的秒数
function timest() {
  var tmp = Date.parse( new Date() ).toString();
  tmp = tmp.substr(0,10);
  return tmp;
}


module.exports = router;

记得填写自己的小程序appid和绑定的商户号
在这里插入图片描述
填写自己的小程序秘钥
在这里插入图片描述
填写自己的商户Key
在这里插入图片描述
最后在小程序点击一下看一下支付效果:
在这里插入图片描述

每天进步一点点,开心也多一点点

发布了60 篇原创文章 · 获赞 66 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/weixin_40169642/article/details/88375193