教你用thinkjs框架怎样实现微信支付?

教你用thinkjs框架怎样实现微信支付?

点点

2021-05-25 11:11 阅读 266 喜欢 0

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

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

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

详细的网址: www.sdxlp.cn

微信支付开通

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

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

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

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

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

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

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

微信支付流程

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

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

用户从网站上确定商品及数量等,然后确认购买 生成二维码(支付链接,自己网站的),需要用户从微信扫描才可以(微信公众号的JSSDK开发) 用户扫描二维码后进入确认页面(在进入的过程中,调用微信接口(统一下单)获得prepay_id),然后用户点击页面的“确认支付” 用户点击后,调用微信公众号网页开发的JSSDK的微信支付 支付成功后,微信会发送通知到服务器,此时可以先进行处理。 用户点击确认支付,调用微信的查单接口 至此,整个流程结束,后续就是个人业务,可以查看订单啊之类的了。 以下所有都是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中,提供了如何生成签名的算法以及调用下单和查单的接口。

主要是要防止几个问题:

用户多次下单。 订单超期处理 订单异常及其他数据处理

转载请注明出处: http://sdxlp.cn/article/fufu.html


如果对你有用的话,请赏给作者一个馒头吧 ...或帮点下页面底部的广告,感谢!!

赞赏支持
提交评论
评论信息(请文明评论)
暂无评论,快来快来写想法...
推荐
现在正是山东省交新农合医疗和养老的时期,2022年缴费全部从卡到了网上,相信很多小伙伴跟点点一样,会遇到各种问题,那让点点带您看看该怎样去缴费吧!让我们可以快速的解决生活中的问题,可以节省不少的时间呦!
微信中有很多的小程序,有些可能不是很安全啊!会恶意收集个人的信息,但是这个小程序是100%安全的。 这个是疫情情况下出现的,国家政务服务平台的服务,可放心使用。
情侣交往三年后分手,男人索要恋爱期间的花费,女生哪我的损失哪?
现在自媒体平台发展迅速,许多自媒体者已经实现了月入过万,不少人也跃跃欲试,想要在自媒体平台闯出一片天。 各大平台也出现了一群人,他们说有教程,能够教你轻松做好自媒体平台,实现月入过万。
腾讯小微信是现在十分常用的一款社交软件,有些小伙伴不知道微信聊天记录如何迁移到其他手机/平板微信,接下来小编就给小伙伴们介绍一下具体的操作步骤。
PowerShell 系统禁止运行脚本错误
人生在世,肯定会遇到一些困难与资金上的不足,而此时就会不得不伸手去向别人借钱,渡过眼前的难关。而往往借钱,就可以看清一个人的品质,有的人能够信守承诺,在约定的时间把钱还给别人,并且抱有感恩之心。
华为军团于近日前举办了成立大会,在大会上任正非和各个军团的领导也上台演讲,并且近日公布了大会的一部分视频,让很多网友热血沸腾,纷纷想要知道华为军团组建是什么意思?那么下面就让点点给小伙伴们介绍一下。