微信公众平台支付小白的JSAPI踩坑之路(偏前端)

最近公司要求开发一个微信公众号涉及支付,首次开发微信支付,于是乎我自觉地打开了微信公众平台的开发文档,看到零散的开发步骤及各种参数的定义,加之后来痛苦的调试过程中, 我觉得非常有必要花时间记录一下,文字功底不好,不喜勿喷。

JSAPI使用场景 (浏览器是重点)

这里主要说下JSAPI与H5的区别:
JSAPI:依赖于微信的浏览器,所以公众号一定是选这个API了。
H5:只允许微信以外的浏览器使用(主要用于呼起微信客户端同时唤起支付功能)
建议不知道如何选API的小白,可以参考 https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=2_1

开发前准备

1.首先你需要有三个账号:微信账号,微信公众号,微信商户号,同时将公众号接入到商户号。

微信公众号可以由个人注册,但是微信商户号官方可是不支持的个人申请的,在提交资料审核的时候你会知道了,
这里看到网上个人申请商户号的一个办法,https://blog.csdn.net/weixin_39927850/article/details/79161872 ,不过没试过,等有缘人来校验吧。

2.获取基础信息(开发中会使用到的几个变量)

AppID:由公众号自动分配
AppSecret:在公众号的开发平台手动生成
商户号(mch_id):由商户号自动分配
API密码(key):在商户号的开发平台手动生成

3.开发配置

a) 公众号后台 - 配置域名(JS接口安全域名以及网页授权域名都要设置)
设置路径:开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息 - 修改
官方参考:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
注意:域名必须是已备案的可用域名;
微信公众平台支付小白的JSAPI踩坑之路(偏前端)_第1张图片

b) 商户平台 - 设置支付目录(用于接收支付后的回调目录)
设置路径:商户平台 - 产品中心 - 开发配置
注意:此处的目录必须是调用支付请求的html文件所在的目录。
举个栗子:访问地址为http://pay.qq.com/pay/index.html ,授权目录就是http://pay.qq.com/pay/
微信公众平台支付小白的JSAPI踩坑之路(偏前端)_第2张图片

开发步骤

要发起支付不是只用调一个接口就可以实现的,先上个流程图:
微信公众平台支付小白的JSAPI踩坑之路(偏前端)_第3张图片
第一步:获取用户授权及code
开发步骤:
a) 打开H5页面时,先页面跳转至静默授权页面,
b) 通过授权后,页面会自动跳转至首页,但此时跳转的url会新增一个code的参数
c) 可以获取code了

var local = window.location.href ;
var code = getParam('code');
if (code === null || code === '') {
	// 跳转至授权地址,该地址只支持微信浏览器打开
    window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + encodeURIComponent(local) + "&response_type=code&scope=snsapi_base#wechat_redirect";
}else{
	getOpenId(code);
}
// 获取url中的参数
function getParam(paramName) {
	var paramValue = "", isFound = !1;
    if (this.location.search.indexOf("?") == 0 && this.location.search.indexOf("=") > 1) {
        arrSource = unescape(this.location.search).substring(1, this.location.search.length).split("&"), i = 0;
        while (i < arrSource.length && !isFound) arrSource[i].indexOf("=") > 0 && arrSource[i].split("=")[0].toLowerCase() == paramName.toLowerCase() && (paramValue = arrSource[i].split("=")[1], isFound = !0), i++
    }
	return paramValue == "" && (paramValue = null), paramValue;
}     

参数说明
appid 公众号的唯一标识
redirect_uri 授权后重定向的回调链接地址, 请使用 urlEncode对链接进行处理
response_type 返回类型,直接填写code
scope 应用授权作用域
snsapi_base(不弹出授权页面,直接跳转,只能获取用户openid),
snsapi_userinfo(弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )

#wechat_redirect 无论直接打开还是做页面302重定向时候,必须带此参数

注意:每次打开页面的code都会改变,过期时间只有5分钟,且每个code只能使用一次

第二步:用code获取用户openId

如下提供的参考文档是服务器端的,也明确提出该请求必要由服务器端发起,所以后台同事必须提供一个能由前端被调起的接口

官方参考(后端):https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
微信公众平台支付小白的JSAPI踩坑之路(偏前端)_第4张图片

function getOpenId(code) {
    $("#loading").show();
    var data = new FormData();
    data.append("code", code);
    $.ajax({
        type: "POST",
        url: "http://127.0.0.0:8888/wx/getWxOpenId.do",
        cache: false,
        data: data,
        processData: false,
        contentType: false,
        dataType: "json",
        success: function (json) {
            if (json.errcode) {
                alert("获取openId失败 :" + json.errmsg);
            } else {
                openId = json.openid;
            }
        }, complete: function (res) {
            $("#loading").hide();
        }, error: function (res) {
            alert("服务器报错:" + res.statusText);
        }
    })
}

注意:openId是微信用户的唯一标识,每个微信用户都拥有自己固定的openId

第三步:点击支付时,先用openId,key获取prepayid;
同第2步,这里需要后台同事配合实现数据转发,在后台调用"统一下单"的接口,生成订单并将prepayid返回至前端

官方参考(后端):https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

// 获取商品id
function getProuctId() {
    $("#loading").show();
    var data = new FormData();
    data.append("openid", openId);
    data.append("apiKey", key);      // 在商户号的开发平台手动生成,API密码
    $.ajax({
        url: "http://127.0.0.0:8888/wx/weixinPay.do",
        type: 'POST',
        cache: false,
        data: data,
        asyns: false,
        processData: false,
        contentType: false,
        success: function (res) {
            productId = res.prepayid;
            productInfo = res;
            if (productId) {
                 onBridgeReady();
            }
        }, complete: function (res) {
            $("#loading").hide();
        }, error: function (res) {
            alert("服务器报错:" + res);
        }
    })
}

第四步:生成签名,并吊起微信支付, 此处使用的是SHA256加密
官方参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6

 // 发起支付
 function onBridgeReady() {
    var data = {
        "appId": appid,     //公众号名称,由商户传入        
        "nonceStr": productInfo.noncestr, //随机串     
        "package": "prepay_id=" + productInfo.prepayid,          // 单号
        "signType": "HMAC-SHA256",
        "timeStamp": parseInt(new Date().getTime() / 1000).toString()         //时间戳,自1970年以来的秒数
    }
    data.paySign = createSign(data);         // 微信签名
    WeixinJSBridge.invoke(
        'getBrandWCPayRequest', data,
        function (res) {
            if (res.err_msg == "get_brand_wcpay_request:ok") {
                alert("支付成功");
            } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
                alert("支付过程中用户取消");
            } else if (res.err_msg == "get_brand_wcpay_request:fail") {
                alert("支付失败");
            }
        });
}
// 生成签名
function createSign(data) {
    var stringA;
    var array = [];
    for (var obj in data) {
        array.push(obj + "=" + data[obj]);
    }
    stringA = array.join("&") + "&key=" + key;
    $("#SHA256").val(CryptoJS.HmacSHA256(stringA, key));
    return $("#SHA256").val().toUpperCase();
}

参数说明
微信公众平台支付小白的JSAPI踩坑之路(偏前端)_第5张图片

问题总结:
签名部分是问题高发的关键一步,基本调用支付不成功都是因为签名无效导致的,生成签名的方式不多说,看官网https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3,很详细。

重点说一下,生成签名的几个需要注意的参数规则:

1、timeStamp(时间戳):实际类型是 String(10), 取值为秒级别的,而不是默认的毫秒级别;
2、nonceStr(随机字符串): 必须是String(32),不要相信官网推荐的调用随机数函数(16位),必须是32位
3、signType(加密方式):可能跟官方的SDK版本有关,默认不一定是MD5;
4、参数的顺序,已参数名的ASCII码从小到大排序(字典序);
5、上诉参数规则必须跟后台签名规则一致,在调用统一下单时,也会有一个签名过程,前端吊起支付这一次算是二次签名了,两次的签名规则必须一致;
6、后台签名规则的sign_type其实是必传字段(官网提示的非必传);
7、注意前后端签名参数的大小写是不一样的,一定不要弄错了;
8、生成的签名中字母转化成大写

PS:
任何一个参数不对都会导致签名失败;
微信官方虽然提供了签名校验工具,但是通过校验的也只能说明你的MD5或SHA256算法跟微信官方的一致;
签名校验工具通过校验,但还是经常出现签名失败的报错,多是因为参数规则不对,或两次签名规不一致
第一次签名校验通过,也不代表第一次签名是没有问题的,要吊起支付,需要前后台的两次签名共同反复多次调试。

签名校验工具
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1

你可能感兴趣的:(问题记录)