微信小程序支付接口退款接口(后端node)

本文记录了使用Node.js实现微信小程序支付和退款接口的过程,包括参数设置、签名生成和回调地址等关键步骤,涉及JSAPI支付方式。详细介绍了每个参数的含义和注意事项,并提供了相关代码示例。
摘要由CSDN通过智能技术生成

来讲讲微信支付吧,看到微信官方文档里好像没有node写的库和sdk,就去百度,然后看到有个哔哩哔哩视频教程。怕以后找不到了就写个博客记录一下,如有问题或者有侵权请及时联系。

哔哩哔哩视频链接:
https://www.bilibili.com/video/BV1mE411w73k?p=3&spm_id_from=pageDriver

//微信官方文档
https://developers.weixin.qq.com/miniprogram/dev/api/payment/wx.requestPayment.html

//微信支付官方文档
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

这是后端的文件目录
在这里插入图片描述
如下图所示需要的参数这里一一填写:
在这里插入图片描述

1.将公众账号ID和商号以及商户秘钥写在一个js文件里导出
在这里插入图片描述
2.随机字符串

注意:随机字符串,不长于32位
    let str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    let res = ''
    for(let i=0;i<32;i++){
        let num = Math.floor(Math.random()*str.length);    //随机生成32位数字
        res+=str[num]          //拿取str里的下标生成32位随机字符串
    };

3.商品描述

body:"test",    //随便写一个

4.商户订单号

注意:商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。为了防止重复我们获取时间这样就不会重复了。如2009年12月25日9点10分10秒表示为20091225091010。
    let date = new Date();
    let arr = [
        date.getFullYear(),
        (date.getMonth()+1),
        date.getDate(),
        date.getHours(),
        date.getMinutes(),
        date.getSeconds(),
        date.getMilliseconds(),
        Math.floor(Math.random()*100000)
    ];
    arr.join('')

5.订单金额随便写了

注意:订单总金额,单位为分,只能为整数

6.获取终端IP
这里百度有挺多的我就随便拿了一个

	var os = require('os');


    let IPAddress = '';
    var interfaces = os.networkInterfaces();
    for (var devName in interfaces) {
      var iface = interfaces[devName];
      for (var i = 0; i < iface.length; i++) {
        var alias = iface[i];
        if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
          IPAddress = alias.address;
        }
      }
    }

7.通知地址

注意:异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。公网域名必须为https,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用http。

我这里也是随便写了一个

8.交易类型

注意:JSAPI -JSAPI支付、NATIVE -Native支付。APP -APP支付。我这里用的JSAPI支付。

9.用户标识

注意:trade_type=JSAPI时(即JSAPI支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识。这也是必传参数。
let config = {
  appid:'11111',     //微信小程序AppID
  secret:'2222 '  //微信小程序AppSecret
}

//获取openid
router.get('/getopenid',(req,res)=>{  
        if(req.query.code){
          request({
                url:'https://api.weixin.qq.com/sns/jscode2session',
                qs: {
                  appid: config.appid,
                  secret: config.secret,
                  js_code: req.query.code,
                  grant_type: 'authorization_code'
                }
          },
          (err,response,body)=>{
                  if(err){
                    return res.json(err)
                  }
                  return res.json(JSON.parse(response.body))
          })
        }
})

最后整合一下
index.js文件

let express = require("express")
const app = new express();
 
let wx_router = require('./router/wx')

app.use('/wx',wx_router)
 
//设置监听端口
app.listen(3000);
console.log("[server] start listening at port 3000");

utils下的util.js

var os = require('os');

// 32位随机字符串
function getRnd32(){
    let str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    let res = ''
    for(let i=0;i<32;i++){
        let num = Math.floor(Math.random()*str.length);
        res+=str[num]
    };
    return res;
}

//时间戳
function getTimeStamp(){
    return Math.round(new Date().getTime()/1000)
}

//商品订单号
function getTradeNo(){
    let date = new Date();
    let arr = [
        date.getFullYear(),
        (date.getMonth()+1),
        date.getDate(),
        date.getHours(),
        date.getMinutes(),
        date.getSeconds(),
        date.getMilliseconds(),
        Math.floor(Math.random()*100000)
    ];
    return arr.join('')
}


// 获取ip
function getIPAddress() {
    let IPAddress = '';
    var interfaces = os.networkInterfaces();
    for (var devName in interfaces) {
      var iface = interfaces[devName];
      for (var i = 0; i < iface.length; i++) {
        var alias = iface[i];
        if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
          IPAddress = alias.address;
        }
      }
    }
    return IPAddress;
  };

module.exports = {
    getRnd32,getTimeStamp,getTradeNo,getIPAddress,
}

config文件夹下的index.js

let WX_INFO = {
    WX_APP_ID:"111",      //公众号appid
    WX_MCH_ID:'111',        //商号
    WX_SHOP_KEY:'111'     //商户秘钥
}

module.exports = {
    WX_INFO
}

router下的wx.js

let express = require('express')
let router = express.Router()
let request  = require('request')
let WX_INFO = require('../config/index')
let util = require('../utils/util')

let config = {
  appid:'1111',     //微信小程序AppID
  secret:'2222'  //微信小程序AppSecret
}

//获取openid
router.get('/getopenid',(req,res)=>{  
        if(req.query.code){
          request({
                url:'https://api.weixin.qq.com/sns/jscode2session',
                qs: {
                  appid: config.appid,
                  secret: config.secret,
                  js_code: req.query.code,
                  grant_type: 'authorization_code'
                }
          },
          (err,response,body)=>{
                  if(err){
                    return res.json(err)
                  }
                  return res.json(JSON.parse(response.body))
          })
        }
})


//支付
router.get('/getPayid',(req,res)=>{
  let openid = req.query.openid;
    let payobj = {
        appid:WX_INFO.WX_INFO.WX_APP_ID,        //公众号appid
        body:"test",                            //商品描述
        mch_id:WX_INFO.WX_INFO.WX_MCH_ID,       //商户号
        nonce_str:util.getRnd32(),              //自己生成的32位随机字符串
        notify_url:"127.0.0.1:3000/wx/success", //支付结果通知地址
        openid,                                 //用户的openid
        out_trade_no:util.getTradeNo(),         //自己生成的商户订单号
        spbill_create_ip:util.getIPAddress(),   //终端ip
        total_fee:1,                            //标价金额
        trade_type:"JSAPI"                      //交易类型
    }
})

module.exports = router;

最难的地方来了那就是签名

我们要对数据进行拼接加密以及转义具体看如下
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3
在这里插入图片描述
我们需要循环router下的wx.js里支付下的payobj转换一下数据形式进行拼接。

我们先npm一下md5

npm i md5

//拼接加密
function getSign(payobj,wx_key){
    let arr = [];
    for(let key in payobj){
        arr.push(key + "=" +payobj[key])       //转换数据的形式appid=wxd930ea5d5a258f4f
    }
    arr = arr.sort(function(a,b){
        return a.localeCompare(b)    //用本地特定排序规则对字符串数组进行排序:
    })
    
//以上是开发文档里的stringA我们需要在最后拼接key微信商户平台
    arr.push("key="+wx_key);
    let str = arr.join("&")   //最后转换字符串以&拼接

    return md5(str)   //md5加密
}

以上是对象形式我们需要转义
先npm一下fast-xml-parser

npm i fast-xml-parser  --save

最后我们进行转义

let express = require('express')
let router = express.Router()
let request  = require('request')
let WX_INFO = require('../config/index')
let util = require('../utils/util')
let Parser = require('fast-xml-parser')
var fs = require("fs")
let j2xParser = new Parser.j2xParser()


//支付
router.get('/getPayid',(req,res)=>{
  let openid = req.query.openid;
    let payobj = {
        appid:WX_INFO.WX_INFO.WX_APP_ID,        //公众号appid
        body:"test",                            //商品描述
        mch_id:WX_INFO.WX_INFO.WX_MCH_ID,       //商户号
        nonce_str:util.getRnd32(),              //自己生成的32位随机字符串
        notify_url:"127.0.0.1:3000/wx/success", //支付结果通知地址
        openid,                                 //用户的openid
        out_trade_no:util.getTradeNo(),         //自己生成的商户订单号
        spbill_create_ip:util.getIPAddress(),   //终端ip
        total_fee:1,                            //标价金额
        trade_type:"JSAPI"                      //交易类型
    }
})

payobj.sign = util.getSign(payobj,WX_INFO.WX_INFO.WX_SHOP_KEY)      //md5加密
let obj  ={xml:payobj}
let sendXml = j2xParser.parse(obj)             //XML转义

最后请求微信接口

    request({
        method:"POST", 
        url:"https://api.mch.weixin.qq.com/pay/unifiedorder",       //下单接口链接
        form:sendXml       //转义的数据
    },(err,response,data)=>{
        if(err) return res.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值