thinkjs框架实现微信支付

thinkjs框架实现微信支付

月光魔力鸭

2020-03-12 13:50 阅读 1109 喜欢 2 thinkjs 微信支付

想做微信/支付宝支付很久了..奈何需要的资质太多,只能慢慢申请,等待,审核..终于下来了。

本篇文章主要从我个人的角度简单介绍下微信支付开通及通过nodejthinkjs框架来搭建的微信支付的流程和相关的函数。

代码这块可能不够严谨,仅供参考,目前还未正式上线,只是开发走通了,当前涉及的支付接口很简单,没有什么分销之类的,为个人的小店做的准备。

微信支付开通

之前在使用微信支付前,一直是用的手机接收通知然后进行推送,不过一个是不方便,手机要一直有电,而且应用不能被杀,就这样还有可能漏单,需要手工去操作.最最最关键的是,如果想上一个新的商品,那么价格必须是唯一的,还要手动创建提交二维码.炒鸡烦人。

闲话少说,开通微信支付目前必须是组织(公司/个体户),个人是无法直接对接的,支付宝也是这样的。

我现在注册的是个体户,山东这边的,可以直接从网上申请,全程网上申请,最后给邮寄过来。

山东的政务地址:http://218.57.139.23:10010/psout/jsp/gcloud/iaicweb/homepage/login.jsp ,注册登录后,根据提示进行填写即可。

这里扯一些别的,个体户注册成功,拿到营业执照后,最好是刻个章(后续各种申请啥的到没用到,不过申请微信开发平台的网站应用的时候用到了),然后是税务登记,还有就是每年的年报(http://www.gsxt.gov.cn/index.html)。

当你有了营业执照后,以下不一定是必须的,只是按照我的路子写的。 我是申请了个服务号,当然还要审核,花钱啥的..很是费劲。


顺手打个广告,服务号:采然,为广大宝妈宝爸准备的各类幼儿教育资源,目前主要是故事、诗词、成语、绘本等。


有了公众号,后面在公众号里面有微信支付,直接点击申请就可以了。(这里面各种资料的填写就不多说了..真要说几千字估计都玄,反正也没办法个性化,按照要求填写申请就行。)

微信支付流程

现在的情况是已经开通微信支付了,接下来如何做呢?怎么开发?怎么调用接口呢? 以下是我个人开通JSAPI的调用过程。

简述下我个人商店的支付流程:

以下所有都是nodejs代码,框架为thinkjs3.0 .

创建二维码
const qr_image = require('qr_image');//二维码生成使用的qr_image
let qrPath = 'http://demo.com/pay?id='+orderId;
let imageObj = qr_image.imageSync(qrPath);
let base64str = 'data:image/png;base64,'+(imageObj.toString('base64'));
//生成二维码后,转成base64字符串,下发到前台进行展示。
创建订单(调用微信统一下单)

先贴文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

实现很简单,就是走下post调用下接口就OK了。

//这里是用用的thinkjs service 实现的。
let wxpay = this.service('weixinpay',{
//公众号appid
    appid : this.config('site').wxappid.value,
//商户号
    mch_id : this.config('site').wxmch_id.value,
//交易密钥
    key : this.config('site').wxpaysecret.value,
//用户的openid,至于如何拿到是公众号开发的那部分,这里不描述了。
    openid : openId
})
//创建支付订单
let notifyUrl = this.config('site').domain.value+'/pay/notify';
//生成支付随机码,并更新
let orderNonceStr = uuid.v4().toString().replace(/-/g,'');
//提前存储,后续校验
await this.model('weixin_order').where({id : orderRecord.id}).update({noncestr : orderNonceStr,openid : openId});
orderRecord.noncestr = orderNonceStr;
//调用下单接口
let rst = await wxpay.createOrder(orderRecord,this.ctx.ip,notifyUrl);
wxpayService 代码
/**
 微信支付-thinkjs3.0
***/

const axios = require('axios');
const crypto = require('crypto');
const xml2json = require('xml2json');
const moment = require('moment');

module.exports = class extends think.Service{
    constructor(opts){
        super();
        this.opts = opts || {
            appid : '',
            mch_id : '1573621291',
        };
    }

    //根据对象生成微信支付xml数据
    __createXML(object){
        let str = `<xml>`;
        for(let key in object){
            str += '<'+key+'>'+(typeof object[key] == 'object' ? ('<![CDATA['+JSON.stringify(object[key])+']]>') : object[key])+'</'+key+'>';
        }
        return str+'</xml>';
    }
    //签名校验--统一下单签名
    __createSign(object,key){
        let paramsArr = [];
        let keyarr = Object.keys(object).sort();
        keyarr.forEach(item=>{
            if(object[item] && item != 'sign'){
                paramsArr.push({
                    name : item,
                    value : typeof object[item] == 'object' ? JSON.stringify(object[item]) : object[item]
                })
            }
        })
        let str = paramsArr.map(item=>{
            return item.name+'='+item.value;
        }).join('&');
        str += '&key='+key;
        console.log(key);
        //做md5
        return crypto.createHash('md5').update(str).digest('hex').toString().toUpperCase();
    }

    /***
     * 微信支付查询
     * @param orderId : 系统内部的订单ID
     * @param nonce_str : 随机32位字符串
     */
    async orderQuery(orderId,nonce_str){
        let url = `https://api.mch.weixin.qq.com/pay/orderquery`;
        let params = {
            appid : this.opts.appid,
            mch_id : this.opts.mch_id,
            // transaction_id : transaction_id,
            out_trade_no : orderId,
            nonce_str : nonce_str,
            sign_type : 'MD5'
        };
        //签名认证
        let sign = this.__createSign(params,this.opts.key);
        params.sign = sign;
        //创建xml字符串
        let xml = this.__createXML(params);
        let resultData = await axios.post(url,xml).then(rs=>rs.data);
        console.log(resultData)
        //xml 转 json
        let resultObject = xml2json.toJson(resultData);
        resultObject = JSON.parse(resultObject);
        //处理返回结果
        return resultObject;
    }
    /**
     *
     * 创建微信支付统一订单
     *
     ***/
    async createOrder(orderRecord,ip,notifyUrl){
        let url = `https://api.mch.weixin.qq.com/pay/unifiedorder`;
        let times = + new Date();
        let starttime = moment(times).format('YYYYMMDDHHmmss');
        let endtime = moment(times+(5*50*1000)).format('YYYYMMDDHHmmss');
        let params = {
            //公众号appid
            appid : this.opts.appid,
            //商户号
            mch_id : this.opts.mch_id,
            //设备号
            device_info : 'WEB',
            //随机字符串
            nonce_str : orderRecord.noncestr,
            //签名类型
            sign_type : 'MD5',
            //商品描述-该内容需要按照微信规范写入*****
            body : '采然-软件开发',
            //商品详情
            detail : {
                //订单原价,分
                cost_price : orderRecord.price,
                receipt_id : orderRecord.id,//小票ID
                goods_detail : [
                    {
                        goods_id : orderRecord.id,
                        goods_name : orderRecord.name,
                        //商品数量
                        quantity : orderRecord.num,
                        //单价,分
                        price : orderRecord.danjia
                    }
                ]
            },
            //附加数据,原样返回
            attach : 'WEB支付['+orderRecord.noncestr+']',
            //商户订单号
            out_trade_no : orderRecord.id,
            //标价币种
            fee_type : 'CNY',
            //总金额:最小单位分*****注意
            total_fee : orderRecord.price,
            //终端IP
            spbill_create_ip : ip,
            //订单生成时间
            time_start :  starttime,
            //订单失效时间,超过5分钟
            time_expire : endtime,
            //通知地址
            notify_url : notifyUrl,
            trade_type : 'JSAPI',
            //系统内自定义,商品ID
            product_id : orderRecord.goodid,
            //限制不能使用信用卡
            limit_pay : 'no_credit',
            //当前付款用户的openid
            openid : this.opts.openid,
            //开票入口,当前不支持开票
            receipt : 'N',


        };
        //获得签名
        let sign = this.__createSign(params,this.opts.key);
        params.sign = sign;

        //获得xml
        let xml = this.__createXML(params);
        //请求返回数据
        let resultData = await axios.post(url,xml).then(rs=>rs.data);
        //对返回结果进行校验和判断。
        let resultObject = xml2json.toJson(resultData);
        resultObject = JSON.parse(resultObject);
        //返回成功,获取prepay_id
        if(resultObject.xml.return_code == 'SUCCESS' && resultObject.xml.result_code=='SUCCESS'){
            let payid = resultObject.xml.prepay_id;
            return {
                success : true,
                payid : payid,
                expiretime : endtime//支付超期,用于再次进入查询使用
            }
        }
        return {
            success : false,
            msg : resultObject.xml.return_msg
        };
    }
}

在这个service中,提供了如何生成签名的算法以及调用下单和查单的接口。

其他的东东

其他的没啥说的,主要是要防止几个问题:


整体说来,这里面最困难的可能就是各种申请了吧,从开始到开发经历了几个月,当然,这也是我三天打鱼两天晒网的问题。 真正准备开发到现在开发走通,一个晚上就实现了。

转载请注明出处: https://chrunlee.cn/article/weixin-pay-in-thinkjs.html


感谢支持!

赞赏支持
提交评论
评论信息 (请文明评论)
暂无评论,快来快来写想法...
推荐
在日常开发中,经常会频繁的做一些重复性的操作,作为一名程序员,解放双手的时刻到了
前段时间帮朋友下歌放在车上听..结果好多都是ncm格式,伤心 ,搜索了下发现基本上这格式解密有好多昂,可惜UI我都不太想要..决定抄一下,自己做一个。 这里先记录下核心代码,回头补充个UI 做个小程序。
thinkjs框架使用ueditor记录。
写文章总会需要一些素材,但是好多素材都是收费或有限制的,还是我要求不高,在千库网看了下还不错,有各签到还送VIP,于是就有了想法....
最近由于系统需要一些数据进行测试,但是正常的流程都是下载pdf ,打印pdf,然后通过涂写答题卡,将涂写的扫描上传..太麻烦了,想做成简单点,通过程序直接生成..卡在了pdf转图片上,今天抽空找了下库,通过gm可以将pdf转为图片,起码第一步已经实现了,后边的涂学号之前已经做过了。
关于js的编译和压缩,之前做过一个小工具了,主要就是自己项目成员大都没有这部分的技能,导致发布的时候总需要去编译压缩下.. 最终做了个命令行小工具.. 问题不在这里,前一阵子做压缩的时候发现压缩后竟然是undefined.最终才发现是es6的语法问题。
在平时nodejs练习过程中,可能会安装多个不同版本的nodejs,那么我们如何来轻松的管理和切换呢?推荐你一个nvm来试试水
从上面那篇文章过来的,这里分享下nodejs对文件夹以及子文件进行批量删除的实现。