微信小程序调用支付功能 - Nodejs

基础准备

1、注册小程序https://mp.weixin.qq.com/
2、小程序需要交300大洋做认证,可以关联以后商户号(如果没有商户需注册开通)

代码

主体代码

var express = require("express");
var router = express.Router();
var db = require("../src/mysql");
var crypto = require('crypto');
var xml2js = require('xml2js');
var request = require('request');

var bodyparser = require('body-parser');
router.use(bodyparser.urlencoded({ extended: false }));

.....................

console.log(req.query, '获取请求参数');
var orderno = new Date().getTime();	//自定义的商户订单号
var nonce_str = randomStr();    //随机数
var total_fee = Number(req.query.amount) * 100;//订单价格
var reqUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
//签名
var signoption = {
    appid: global.appid,//小程序appid
    body: 'xxxx',//商品描述
    mch_id: global.mch_id,//商户号
    nonce_str: nonce_str,//随机字符串
    notify_url: global.notify_url, //回调地址
    openid: openid,//交易类型是JSAPI的话,此参数必传   可从过code获取openid
    out_trade_no:orderno,//商品订单号
    spbill_create_ip: '111.111.111.111',//因为微信支付需要有回调url,所以没法确定你的公网ip就没法发送订单支付通知给你,所以提供一个解析的正常ip就好
    total_fee: total_fee,//商品价格
    trade_type: 'JSAPI'//交易类型,JSAPI为小程序交易类型
};
var sign = createSign(signoption);
//这个顺序要和签名顺序一致
let formData = '<xml><appid>' + signoption.appid + '</appid><body>' + signoption.body + '</body><mch_id>' + signoption.mch_id + '</mch_id><nonce_str>' + signoption.nonce_str + '</nonce_str><notify_url>' + signoption.notify_url + '</notify_url><openid>' + signoption.openid + '</openid><out_trade_no>' + signoption.out_trade_no + '</out_trade_no><spbill_create_ip>' + signoption.spbill_create_ip + '</spbill_create_ip><total_fee>' + signoption.total_fee + '</total_fee><trade_type>' + signoption.trade_type + '</trade_type><sign>' + sign + '</sign></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, '统一下单接口返回的数据');
        try {
            xml2js.parseString(body, function (error, result) {
                console.log(JSON.stringify(result), 'xml解析成字符串');
                let reData = result.xml;

                let responseData = {
                    timeStamp: new Date().getTime(),
                    nonceStr: reData.nonce_str[0],
                    package: reData.prepay_id[0],
                    paySign: reData.sign[0]
                };
                //更新记录支付结果
               //................
               //个性化业务处理
               res.json({ error_code: 0, result: responseData });
            });
        } catch (e) {
            console.log(e);
        }
    }
});

产生随机数

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;
}

签名

//签名算法(把所有的非空的参数,按字典顺序组合起来+key,然后md5加密,再把加密结果都转成大写的即可)
function createSign(obj) {	
    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=' + global.mch_key;
    var hash = crypto.createHash('md5');
    stringSignTemp = hash.update(stringSignTemp);
    var signValue = hash.digest('hex');
    return signValue.toUpperCase();
}

以下是遇到的坑

  1. spbill_create_ip一定要给一个公网地址,不然可能会报total_fee的问题
  2. 加密的顺序一定不要错,保持一致,不然会签名错误
  3. 参数顺序后最后要加上key=xxxxx 商户的mch_key
小程序端
wx.request({
      url: '接口地址?code=用户code&amount=0.01',
      success(res) {
        console.log(res, '统一下单接口返回信息')
        if (res.data.error_code == 0) {
          //成功
          var _signtext = "appId=小程序appid&nonceStr=" + res.data.result.nonceStr + "&package=prepay_id=" + res.data.result.package + "&signType=MD5&timeStamp=" + res.data.result.timeStamp + "&key=商户mch_key";**//商户key一定要补,顺序不要随便调整**
          var paysign = md5.hexMD5(_signtext);**//md5重新加密生成签名**
          //开始调起支付
          wx.requestPayment({
            timeStamp: res.data.result.timeStamp + '', //统一下单返回
            nonceStr: res.data.result.nonceStr, //统一下单返回
            package: "prepay_id=" + res.data.result.package, **//一定要写prepay_id=   不然会报total_fee错误**
            signType: 'MD5', //签名算法
            paySign: paysign.toUpperCase(), **//不能用统一下单的签名,需重新签名!!!!**
            success(res) {
              console.log(res, '微信支付成功!!!')
              	//个性化业务处理
              })
            }
          })
        } else {
          console.log(res, "支付失败!"+res.msg);
        }
      }
    })

注意:小程序的官方文档一定要小心看,看少一点错误都看不懂
签名测试地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
小程序端签名文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
小程序支付API:https://developers.weixin.qq.com/miniprogram/dev/api/wx.requestPayment.html

参考引用:https://blog.csdn.net/yemuxia_sinian/article/details/86672495

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值