• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

微信小程序支付流程

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

首先,先把官网的流程图放上来,然后按照图一步步的来。

第一步:用户请求开发者后台,发起下单请求

  • 发起请求前在小程序端调用 wx.checkSession() 查看 session_key 是否过期
    • 如果过期了 重新调用 wx.login() 返回 session_key 和 openid
    • 如果没过期 继续下一步操作,请求开发者后台

第二步:开发者查找一下数据库或者缓存里是否有 openid 和 session_key

  • 如果有生成订单编号 out_trade_no
  • 如果没有返回错误消息,缺少 openid 、 session_key

第三步:开发者服务器请求统一下单 API ,带上要求的参数:

appid
mch_id
nonce_str
sign
body
out_trade_no
total_fee
spbill_create_ip

nonce_str 获取随机字符串:

test.js

js

/*
 *  功能: 返回32位随机字符串
 *  create by tiankai on 2018-06-25 15:39
 */
getNonceStr(){
    let char = \'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\';
    let len = 32;
    let result = \'\';
    for(let i = 0; i < len; i++){
        let randomNum = Math.floor(Math.random()*char.length);
        result += char[randomNum];
    }
    return result;
}

sign 参数签名, 第二个tab(js)是调用函数的方法, key 为商户平台设置的密钥 key 

test.js
  • js
  • js
/*
 *  功能:sign 参数签名
 *  create by tiankai on 2018-06-26 12:00
 */
async makeSign(params, key){
    // 生成签名 sign
    let strOrderArr = Object.keys(params).sort();
    let stringA = "";
    strOrderArr.map(val =>{
        //如果参数值为空,或者验证返回的 sign 不参与签名
        if(
            think.isNullOrUndefined(params[val]) ||
            val === \'sign\' ||
            params[val].length === 0
        ) return;
        stringA += val + "=" + params[val] + "&";
    });
    let stringSignTemp = stringA + "key=" + key;
    let sign = think.md5(stringSignTemp).toUpperCase();
    return sign;
}

得到这几个参数就开始发起请求统一下单 API 了,这里需要注意的是,请求参数应该以 xml 的形式传送过去,这里借助一个工具 xml2js 把对象转换为 xml,也可以把 xml 转换为 对象、json。

安装 xml2js

npm i xml2js

使用 xml2js

test.js

 js 

const xml2js = require(\'xml2js\');

//xml->json
//xml2js默认会把子子节点的值变为一个数组, explicitArray设置为false
var xmlParser = new xml2js.Parser({explicitArray : false, ignoreAttrs : true})
//json->xml
var jsonBuilder = new xml2js.Builder();

请求参数转换为 xml

test.js

js

/*
 *  功能:获取统一下单 API 请求XML参数
 *  create by tiankai on 2018-06-25 15:23
 */
async getUnifiedOrderParams(){
    let signString = {
        appid: config.appid,
        mch_id: config.mchid,
        nonce_str: await this.getNonceStr(),
        body: \'短信平台-短信套餐购买\',
        out_trade_no: \'20180926125346\',//订单号
        total_fee: 88,//订单金额
        //APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP
        //需要自行获取,这里只是为了测试直接写上了
        spbill_create_ip: \'123.12.12.123\',
        notify_url: config.notify_url,
        trade_type: \'JSAPI\',
        openid: await think.cache(\'openId\')
    }
    let sign = await this.makeSign(signString,config.key);
    signString.sign = sign;
    /* console.log("--------------------------");
     * console.log(sign);
     * console.log("--------------------------"); */
    let xml = await jsonBuilder.buildObject(signString);
    /* console.log(xml); */
    return xml;
}

然后就可以发起统一下单API请求了

test.js

js

/*
 *  功能:调用统一下单API接口
 *  create by tiankai on 2018-06-26 11:01
 */
async unifiedOrder(){
    let xmlParams = await this.getUnifiedOrderParams();
    let unifiedOrderUrl = config.unifiedOrderUrl;
    let opt = {
        method: "POST",
        mode: \'cors\',
        headers: {
            \'content-type\': \'text/xml\'
        },
        body: xmlParams
    }
    let res = await this.fetch(unifiedOrderUrl, opt);
    //这里微信返回的也是 xml
    let result = await res.text();
    let data = null;
    // 微信返回的 XML 转换为 JSON
    xmlParser.parseString(result,function(err, jsonData){
        if(!err){
            /* console.log(jsonData); */
            data = jsonData;
        }
    });
    return data;
}

第四步:当请求成功时 判断一下 return_code 和 result_code

  • 如果它们都等于 SUCCESS 的时候,微信会把我们需要的预支付订单信息 prepay_id 返回来,
  • 否则返回 return_msg 给前端 展示具体错误

第五步:拿上 prepay_id ,进行再次签名,然后返回给前端

test.js

js

/*
 *  功能:统一下单接口返回 prepay_id 再次签名 返回给前端
 *  create by tiankai on 2018-06-26 15:45
 */
async payParams(){
    let signString = {
        appid: config.appid,
        timeStamp: +new Date(),
        nonce_str: await this.getNonceStr(),
        package: null,
        signType: \'MD5\'
    }
    //调用 统一下单 API
    let jsonData = await this.unifiedOrder();
    if(think.isNullOrUndefined(jsonData) &&
       jsonData.xml.return_code === \'SUCCESS\' &&
       jsonData.xml.result_code === \'SUCCESS\'
    ){
        signString.package = \'perpay_id=\'+jsonData.xml.perpay_id
    }else{
        return jsonData.xml.return_msg;
    }
    //进行再次签名
    let paySign = await this.makeSign(signString,config.key);
    signString.paySign = paySign;
    let { appid, signType, ...result } = signString;
    // result 中不包括 appid 和 signType 返回给前端
    return result;
}

第六步:用户确认支付后,小程序端调用支付接口,根据返回结果提示用户

test.js

js

wx.requestPayment({
   \'timeStamp\': \'\',
   \'nonceStr\': \'\',//后端返回的随机字符串
   \'package\': \'\',//后端返回的
   \'signType\': \'MD5\',
   \'paySign\': \'\',//后端返回的
   \'success\':function(res){
   },
   \'fail\':function(res){
   }
});

第七步:支付成功后,微信服务器会把支付结果返回给配置的 notify_url ,开发者根据支付结果,更新服务器的订单状态。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
微信小程序常见两种登陆注册方式发布时间:2022-07-18
下一篇:
订餐小程序发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap