加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 资源 > 正文

node egg 微信支付服务

发布时间:2020-12-14 19:06:19 所属栏目:资源 来源:网络整理
导读:一、初始化egg应用 npm init egg -- type =simplenpm i复制代码 二、配置微信支付用到的插件 plugin.js 必备插件(egg-wechat-pay可以选择别的插件代替) module.exports = { cors: { enable: true , package: 'egg-cors' ,}, wechatPay: { enable: 'egg-wecha

一、初始化egg应用

npm init egg --type=simple
npm i
复制代码

二、配置微信支付用到的插件

plugin.js 必备插件(egg-wechat-pay可以选择别的插件代替)

module.exports = {
 cors: {
   enable: true,   package: 'egg-cors',}, wechatPay: {
   enable: 'egg-wechat-pay'
 },};
复制代码

三、配置中间件

因为微信支付返回的数据都是xml格式数据 所以我们的解析xml数据 不然接收不到微信支付回调的请求数据

xmlparse.js (可以使用koa的其它中间件也行)

module.exports = require('co-wechat-body');
复制代码

四、配置config.default.js

//部分主要配置
config.security = {
        csrf: {
            enable: false,domainWhiteList: ['*'],}//跨域请求

    const fs = require('fs')
    const path = 'path')
    
    config.mpWeixin = {
        appid: '',微信公众号或小程序号
        AppSecret: 'https://api.weixin.qq.com/',MsgToken: ''
    }
    
    config.wechatPay = {
        client: {
            bodyPrefix: //
            appId: //微信公众号或小程序号
            merchantId: //商户号
            secret: //商户密钥
            notifyUrl: //支付成功回调地址
            REFUNDNotifyUrl: //退款成功回调地址
            pfx: fs.readFileSync(path.join(__dirname,'../app/public/wxpaly/apiclient_cert.p12'))//退款证书地址
        },URLS: {
            UNIFIED_ORDER: 'https://api.mch.weixin.qq.com/pay/unifiedorder',ORDER_QUERY: 'https://api.mch.weixin.qq.com/pay/orderquery',REFUND: 'https://api.mch.weixin.qq.com/secapi/pay/refund',REFUND_QUERY: 'https://api.mch.weixin.qq.com/pay/refundquery',DOWNLOAD_BILL: 'https://api.mch.weixin.qq.com/pay/downloadbill',SHORT_URL: 'https://api.mch.weixin.qq.com/tools/shorturl',CLOSE_ORDER: 'https://api.mch.weixin.qq.com/pay/cloSEOrder',REDPACK_SEND: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack',REDPACK_QUERY: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo',TRANSFERS: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers',TRANSFERS_QUERY: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo',}
    }
复制代码

五、工具函数util.js

const crypto = 'crypto');
const fs = 'fs')
const path = 'path')

function randomString(len) {
  // isFinite 判断是否为有限数值
  if (!Number.isFinite(len)) {
    throw new TypeError('Expected a finite number');
  }
  return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0,len);
}


getSign(params,key,type = 'MD5') {//支付签名
  const paramsArr = Object.keys(params);
  paramsArr.sort();
  const stringArr = []
  paramsArr.map(key => {
    if (key != 'sign' && params[key])
      stringArr.push(key + '=' + params[key]);
  })
  if (type == "MD5") {
    // 最后加上 商户Key
    stringArr.push("key=" + key)
    const string = stringArr.join('&');
    const MD5 = crypto.createHash('md5');
    return MD5.update(string).digest('hex').toUpperCase();
  } else {
    return crypto.createHmac('sha256',key)
      .update(stringArr.join('&'))
      .digest('hex').toUpperCase();
  }

}

checkSign(params,key) { //验证签名是否正确
  const {
    sign
  } = params;
  const Newsign = getSign(params,key)
  if (sign === Newsign) {
    return true
  } false
  }
}


复制代码

六、编写Service

Payment.js

'use strict';
const Service = 'egg').Service;
const { randomString,ransign,getSign,checkSign,} = 'util.js')
const moment = 'moment');
const Decimal = 'decimal.js');
class PaymentService extends Service {
 
    /**
     * H5支付或微信扫一扫支付
     *
     * @param {*} body 费用说明
     * @param {*} money 金额
     * @returns
     * @memberof PaymentService
     */
    async pay(PayType,body,money) {
        const { ctx,service,app } = this;
        let No = Date.now();
        let OrderNo = moment().format('YYYYMMDDHHmm') + randomString(3) + No;
        let createTime = moment().format('YYYY-MM-DD HH:mm:ss');
        let order = { //统一订单参数
            device_info: 'WEB',out_trade_no: OrderNo,total_fee: new Decimal(money).mul(new Decimal(100)).toFixed(),attach: `${UserId}`
        };
        if (PayType == 'H5') {
            order.scene_info = JSON.stringify({
                h5_info: 'h5_info',type: 'Wap',wap_url: this.config.h5host,wap_name: '峰会报名付款'
            })
        }
        const unifiedRes = await this.unifiedOrder(order,PayType == 'H5' ? 'MWEB' : 'NATIVE'); 
        return unifiedRes
    }


   

    //支付回调
    async payaction(params) {
        const {
            ctx,app
        } = const {
            appid,136);">//公众账号ID
            bank_type,136);">//付款银行
            cash_fee,136);">//现金支付金额
            device_info,136);">//设备号
            fee_type,136);">//货币种类
            is_subscribe,136);">//是否关注公众账号
            mch_id,136);">//商户号
            nonce_str,136);">//随机字符串
            openid,136);">//用户标识
            out_trade_no,136);">//商户订单号
            result_code,136);">//业务结果
            return_code,136);">//返回状态码
            sign,136);">//签名
            time_end,136);">//支付完成时间
            total_fee,136);">//订单金额
            trade_type,136);">//交易类型
            transaction_id,136);">//微信支付订单号
            attach
        } = params;

        if (return_code == "SUCCESS") {
            if (checkSign(params,this.config.wechatPay.client.secret)) {//解析回调数据是否正确
               //自己处理
            } else {
                return {
                    msg: '签名错误',status: 'error',}
            }
        } else {
            return {
                msg: '支付失败',}
        }
    }



 

    //退款
    async refund(out_trade_no,refund_fee,refund_desc,PayPrice) {
        this;

     
        let nonce_str = randomString(32);
 
            let out_refund_no  = moment().format('YYYYMMDDHHmmss') + randomString(25);

            let data = {
                appid: this.config.wechatPay.client.appId,mch_id: this.config.wechatPay.client.merchantId,nonce_str,136);">//随机字符串
                out_trade_no,136);">//订单号
                out_refund_no,136);">//退款订单号
                total_fee: new Decimal(PayPrice).mul(//总金额
                refund_fee: new Decimal(refund_fee).mul(//退款金额
                refund_desc,136);">//退款原因描述
                notify_url: this.config.wechatPay.client.REFUNDNotifyUrl//退款成功回调地址
            }
            let sign = getSign(data,51); font-weight: 700;">this.config.wechatPay.client.secret);//签名
            let xml = {
                ...data,sign
            };
            try {
                const curlres = await ctx.curl(${this.config.wechatPay.URLS.REFUND}`,{
                    method: 'POST',pfx: this.config.wechatPay.client.pfx,136);">//退款证书
                    passphrase: // 直接发送原始 xml 数据,不需要 HttpClient 做特殊处理
                    content: this.app.wechatPay.stringify(xml),});
                
                let rdata = this.app.wechatPay.parse(curlres.data);//解析xml数据

                return {
                    res: rdata
                }
            } catch (error) {
                console.log(error,0);">"error");
                if (error == "invalid refund_fee") {
                    return {
                        msg: '退款金额不正确',}
                } else {
                    '退款失败',}
                }

            }

    }

  
    //微信内部浏览器或小程序 统一创建支付 
    async CreatePaymentInfo(money,openid) {
        this;
        
        const order = { body: "",费用说明
            out_trade_no: OrderNo,136);">//订单编号
            total_fee: //支付金额 分为单位
            openid,136);">//用户openid
        };
        const res = this.unifiedOrder(order); //请求生成订单信息
        return {
            res
        }
    }

    async unifiedOrder(order,trade_type = 'JSAPI') {
        32);//随机字符串
        let Data = {
            appid: sign_type: 'MD5',136);">//签名方式
            spbill_create_ip: ctx.ip,136);">//用户ip
            trade_type,136);">//支付类型
            notify_url: this.config.wechatPay.client.notifyUrl,136);">//支付成功回调地址
            time_expire: moment().add(1,0);">'h').format('YYYYMMDDHHmmss'),...order
        }

        let sign = getSign(Data,136);">//签名
        let xml = {
            ...Data,sign
        };
        const cur = this.config.wechatPay.URLS.UNIFIED_ORDER}`,{
            method: // 直接发送原始 xml 数据,不需要 HttpClient 做特殊处理
            content: const parseData = this.app.wechatPay.parse(cur.data);
        let res = {
            appId: Data.appid,nonceStr: nonce_str,package: `prepay_id=${parseData.prepay_id}`,timeStamp: moment().add('h').unix().toString(),signType: if (trade_type == 'MWEB') {//手机浏览器H5支付
            res.mweb_url = parseData.mweb_url
        }

        'NATIVE') {//可用于微信扫一扫支付
            res.code_url = parseData.code_url
        }

        return {
            ...res,paySign: getSign(res,51); font-weight: 700;">this.config.wechatPay.client.secret)
        }
    }
    
}

module.exports = PaymentService;
复制代码

主要代码基本可以实现微信支付的服务端

写的太糙了hhh 不会写只能贴代码 有什么问题 可以留言

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读