微信公众号调起微信内置浏览器h5支付

(一)微信公众号和微信商户平台配置

根据微信公众平台的使用教程配置

 

 

一、设置支付目录

请确保实际支付时的请求目录与后台配置的目录一致,否则将无法成功唤起微信支付。

在微信商户平台(pay.weixin.qq.com)设置您的公众号支付支付目录,设置路径:商户平台-->产品中心-->开发配置,如图7.7所示。公众号支付在请求支付的时候会校验请求来源是否有在商户平台做了配置,所以必须确保支付目录已经正确的被配置,否则将验证失败,请求支付不成功。

支付目录配置

图7.7 微信公众号支付-支付目录配置

二、设置授权域名

开发公众号支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。具体界面如图7.8所示:

微信网页授权域名微信网页授权域名

图7.8 微信网页授权域名设置

 

三、配置商户秘钥key

 

参考文章https://jingyan.baidu.com/article/75ab0bcbbf7034d6864db2c3.html

注意配置秘钥后要自己保存秘钥,商户平台上不能查看秘钥。后面的签名算法需要用到商户秘钥。

(二)统一下单

一、配置和参数

参考文档,需要注意的是:

1.微信支付结果通知的回调地址notify_url必须是80端口,如果不是80端口的话可以通过nginx反向代理

2.交易类型这里是公众号支付,填JSAPI

3.openid,公众号支付即trade_type=JSAPI时,此参数必传,此参数是前端微信登录后获取的openid

二、代码实现

1.nodejs做后台实现统一下单接口

 

h5_order: function(attach, body, mch_id, openid, out_trade_no, total_fee, notify_url,spbill_create_ip,scene_info) {
    var deferred = Q.defer();
    var appid = "wx4280cd3b0ecf2a38";//"wx7df91d705b3f0a15";   // h5的appid
    var nonce_str = this.createNonceStr();
    var trade_type = "JSAPI";
    var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    var spbill_create_ip = "115.192.87.205";//写死了这边
    var formData = "<xml>";
    formData += "<appid>" + appid + "</appid>"; //appid  必填
    //formData += "<attach>" + attach + "</attach>"; //附加数据
    formData += "<body>" + body + "</body>";   //必填
    formData += "<mch_id>" + mch_id + "</mch_id>"; //商户号  //必填
    formData += "<nonce_str>" + nonce_str + "</nonce_str>"; //随机字符串,不长于32位。 //必填
    formData += "<notify_url>" + notify_url + "</notify_url>";  //必填
    formData += "<openid>" + openid + "</openid>";
    formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>";  //必填
    formData += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>";  //IP地址需要动态获取 //必填
    formData += "<total_fee>" + total_fee + "</total_fee>";  //必填
    formData += "<trade_type>" + trade_type + "</trade_type>";  //必填
    //formData += "<sign>" + this.getSign(appid, mch_id, "", body, nonce_str) + "</sign>";  //  getSign: function(appid, mch_id, device_info, body, nonce_str) {
    //formData += "<scene_info>" + JSON.stringify(scene_info) + "</scene_info>";
    formData += "<sign>" + this.signOne(appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, "JSAPI") + "</sign>";
    formData += "</xml>";

    //console.log("formData:"+formData);
    var self = this;
    request({
        url: url,
        method: 'POST',
        body: formData
    }, function(err, response, body) {
        if (!err && response.statusCode == 200) {
            console.log(body);
            var parser = new xml2js.Parser({ trim:true, explicitArray:false, explicitRoot:false });//解析签名结果xml转json
            parser.parseString(body, function(err, result){
                var prepay_id = result['prepay_id'];
                var timeStamp = self.createTimeStamp();
                var package="prepay_id="+prepay_id;
                var _paySignjs = self.signTwoH5(appid, nonce_str, package,timeStamp,"MD5");
                var args = {
                    appId: appid,
                    package: package,
                    timeStamp: timeStamp,
                    nonceStr: nonce_str,
                    paySign: _paySignjs
                };
                //console.log("进行二次签名后数据", args);
                deferred.resolve(args);
            });
        } else {
            console.log(body);
        }
    });
    return deferred.promise;
},

2.签名函数signOne:

 

signOne: function(appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type) {
    //参数名ASCII码从小到大排序(字典序)
    var ret = {
        appid: appid,//ok
        //attach: attach,
        body: body,//ok
        mch_id: mch_id,//ok
        nonce_str: nonce_str,//ok
        notify_url: notify_url,
        openid: openid,
        out_trade_no: out_trade_no,
        spbill_create_ip: spbill_create_ip,
        total_fee: total_fee,
        trade_type: trade_type    //类型
    };
    var string = this.raw(ret);
    string = string + '&key=' + key; //key为在微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
    console.log("signOne string:"+string);
    var crypto = require('crypto');
    var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex');//md5加密操作
    return sign.toUpperCase();//转换成大写字母
},

 
//拼接
raw: function(args) {
    var keys = Object.keys(args);
    keys = keys.sort()
    var newArgs = {};
    keys.forEach(function(key) {
        newArgs[key] = args[key];
    });
    var string = '';
    for (var k in newArgs) {
        string += '&' + k + '=' + newArgs[k];
    }
    string = string.substr(1);
    return string;
}

2.签名函数signTwoH5:

 

signTwoH5: function(appid, nonceStr, package,timestamp,signType) {
    var ret = {
        appId: appid,
        nonceStr: nonceStr,
        package: package,
        timeStamp: timestamp,
        signType:signType,
    };

    var string = this.raw(ret);
    string = string + '&key=' + key;
    console.log("signTwo string:  " + string);

    var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex');
    return sign.toUpperCase();
}

3.生成时间戳和随机字符串函数

 

// 随机字符串产生函数
createNonceStr: function() {
    return Math.random().toString(36).substr(2, 15);
},

// 时间戳产生函数
createTimeStamp: function() {
    return parseInt(new Date().getTime() / 1000) + '';
},

4.服务端生成预支付订单号等信息后发送给前端,前端微信内置浏览器调起支付的代码如下:

 

                    function onBridgeReady(){
 
alert(JSON.stringify(args));
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":args.appId, //公众号名称,由商户传入
"timeStamp":String(args.timeStamp), //时间戳,自1970年以来的秒数
"nonceStr":args.nonceStr, //随机串
"package":args.package,
"signType":"MD5", //微信签名方式:
"paySign":args.paySign //微信签名
},
function(res){
 
if(res.err_msg == "get_brand_wcpay_request:ok" ) {// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
if(callback){
callback(0);
}
} else if(res.err_msg == "get_brand_wcpay_request:cancel"){
if(callback){
callback(1);
}
}else{
alert(JSON.stringify(res));
if(callback){
callback(-1);
}
}
 
 
}
);
}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
 
onBridgeReady();
}

有什么错误信息,可以用alert(JSON.stringify(res))打印出来

### UNI-APP 开发微信公众号 (H5) 并集成微信支付 #### 一、准备工作 为了在 Uni-app 中开发微信公众号 H5 应用并集成微信支付功能,需先完成如下准备: 1. **注册微信公众平台账号** - 获取 AppID 和 AppSecret。 2. **配置服务器域名** - 在微信公众平台上设置合法的业务域名、JS接口安全域名等必要信息[^1]。 3. **安装必要的插件和库文件** 对于微信支付的支持,在项目中引入 `wx.js` 文件用于调用微信 JS SDK 接口。同时确保已安装最新版本的 Vue CLI 工具以便更好地管理项目资源。 #### 二、实现流程 ##### (一)初始化环境变量 创建 `.env.development` 或者其他适合当前环境下的配置文件来保存敏感数据如 appId, mchId(商户号), key(密钥),这些参数将在后续请求过程中被使用到。 ```bash VUE_APP_WX_APP_ID=your_app_id_here VUE_APP_MCH_ID=your_merchant_id_here VUE_APP_API_KEY=your_api_key_here ``` ##### (二)获取预支付订单编号(prepay_id) 当用户确认付款金额后,前端应向自己的服务端发起 POST 请求传递商品详情给后台处理逻辑;此时后端负责生成交易单据并向 WeChat Pay API 发送 HTTPS 请求以获得 prepay_id 参数作为响应的一部分返回给客户端应用。 注意:此过程涉及敏感操作建议采用 HTTPS 协议传输数据,并且严格按照官方文档说明构建签名字符串防止篡改攻击风险。 ##### (三)调起微信内嵌浏览器中的支付控件 收到有效的 prepay_id 后即可按照下述方式组装所需参数并通过 wx.chooseWXPay 方法启动内置 Webview 支付界面供顾客输入密码验证身份从而完成整个购物流程: ```javascript // 假设已经获得了prepay_id和其他必需的信息 const payParams = { "appId": process.env.VUE_APP_WX_APP_ID, "timeStamp": new Date().getTime(), "nonceStr": Math.random().toString(36).substr(2), "package": 'prepay_id=' + prepay_id_from_server,// 注意这里的拼接规则可能依据实际情况有所变化 "signType": "MD5", }; // 计算 sign 字段的具体方法请参照 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6 let stringA = Object.keys(payParams) .filter(key => payParams[key]) .map(key => `${key}=${encodeURIComponent(payParams[key])}`) .join('&'); stringA += '&key=' + encodeURIComponent(process.env.VUE_APP_API_KEY); payParams.sign = hex_md5(stringA.toUpperCase()); // 调用 chooseWXPay 进行支付 WeixinJSBridge.invoke( 'getBrandWCPayRequest', payParams, function(res){ if(res.err_msg === "get_brand_wcpay_request:ok"){ alert('支付成功!'); }else{ console.error(`支付失败:${res.err_code}`); } }); ``` 上述代码片段展示了如何利用 JavaScript 实现微信支付的核心部分——即通过 WeixinJSBridge 对象访问原生组件进而引导用户至最终结算环节。值得注意的是实际部署之前还需要针对不同场景做充分测试确保兼容性和稳定性。 #### 三、常见问题排查 如果遇到无法正常唤起支付窗口的情况,请检查以下几点: - 是否正确设置了 jsApiList 数组内的权限项; - 检查 URL 地址是否被列入了公众平台的安全白名单之中; - 确认所有参与计算 Sign 的字段都已被正确定义并且顺序无误; - 测试环境中使用的证书是否有效过期等问题也可能会引起异常行为。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值