微信公众号支付踩坑记

  前两周做微信H5支付,在浏览器端用的,天真地以为app挂到公众号中也能用,结果不行>"<|||| ,只好再对接一次公众号支付,微信的支付对接下来总体感觉就是封装地不如支付宝,文档不完善,坑贼多。本文会主要关注对接过程中所遇到的问题,以及部分实现代码。

1.介绍

  公众号支付(JSAPI支付)是指用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块来完成支付,适用于在公众号、朋友圈、聊天窗口等微信内完成支付的场景。注意公众号支付必须在微信环境中才能生效,在普通浏览器中是不能用的。

  现有微信支付的接口都分为普通商户版、服务商版、银行服务商版,普通商户就是单个商户,服务商版就是一个服务商下面可以挂很多子商户,我这边对接的是服务商版。

  公众号的对接过程大致分为申请公众号、提交资料、签署协议、绑定场景等流程,其中第四步绑定场景是登录公众平台,确认商户号和公众号的绑定关系,这里具体可以参考微信文档



  这里需要注意区分公众号和商户号:

  公众号:微信公众号是开发者或商家在微信公众平台上申请的应用账号,该帐号与QQ账号互通,通过公众号,商家可在微信平台上实现和特定群体的文字、图片、语音、视频的全方位沟通、互动

  商户号:指财付通的支付系统为公司配置的用来存储公司的身份信息、交易信息并处理公司的交易指令的账号。微信支付商户号将直接与公司提供的合法银行卡账户绑定,公司的银行卡账户将根据微信支付商户号的交易情况做相应的资金扣划或归集。说白了就是微信分配用于支付的账户。


2. 实现

  本文不会过多的讲述微信公众号支付实现代码(部分代码可参考微信h5支付),主要从前期配置(这个很重要)和遇到问题这两方面来论述。

2.1 前期配置

  涉及到的域名配置需要分别登陆公众平台和商户平台进行配置。

  在商户平台登陆商户号之后,在产品中心--开发配置中可以设置公众号支付的支付授权目录,这里设置的是在发起支付时使用的域名,如果不设置在发起支付时会报商家存在未配置的参数,请联系商家解决错误。设置如下:

  在公众平台登陆公众号后,需要在开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名,按照微信的要求改就行了。至于为什么微信要设置两个域名,而且分别是在公众平台和商户平台都要设置,这里在说一下,一个是用于获取openid时需要的,一个是支付时需要的,微信要求的没办法,为什么不在一个账号里面设置?那就要问微信了--开发配置页面迁移至商户平台

  注意,这里的配置一定要重视,不然后面获取openid和支付时通不过!!!

2.2 获取openid

  公众号支付必须传用户的openid,在服务商模式下,可传openid(用户标识)或者sub_openid(用户子标识),如果选择传sub_openid,则必须传sub_appid。用户标识其实用户在商户appid下的唯一标识,传openid就用appid获取,传sub_openid则需要通过sub_appid来获取。

  由于我这里只是获取用户的openid,并没有获取用户信息,所以分为2步,具体可以参考微信网页授权

  a  用户同意授权,获取code

public RestResult<String> auth(@RequestBody TradeVo tradeVo){
        String redirectUrl = "";   //注意,此处的域名需要填写前面在公众号平台设置的授权域名
        JSONObject jsonObject = (JSONObject) JSONObject.toJSON(tradeVo);
        String state = jsonObject.toJSONString();
        try{
            redirectUrl = URLEncoder.encode(redirectUrl,"UTF-8");
            state = URLEncoder.encode(state,"UTF-8");
        }catch (Exception e){
            return new RestResult<String>(new ServiceException(e));
        }
        String auth = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx468c78f63c050017&redirect_uri="+redirectUrl+"&response_type=code&scope=snsapi_base&state="+state+"#wechat_redirect";
        return new RestResult<>(auth);
    }

  这里主要是后端将一些业务参数也一起封装到state字段里面了,可以在下一次重定向时使用。该方法返回的是一个url地址,前端收到后端返回后直接跳转到这个地址上,微信会进行授权生成code并将刚才的自定义字段state一起放在一个url后面(就是代码中指定的回调redirect_uri),然后页面会自动重定向到这个地址,我这里的是一个中间页面,这个页面里面会把code和state解析出来再调用后端另外一个接口,就是等下的第2步。。。

  b  通过code换取网页授权access_token

public RestResult getOpenId(@RequestParam("code") String code, @RequestParam("state") String state){
    RestResult restResult = null;
    TradeVo tradeVo = null;
    try{
        getopenId(code);
        tradeVo = ((JSON)JSON.parse(URLDecoder.decode(state,"UTF-8"))).toJavaObject(TradeVo.class);
    }catch (Exception e){
        return new RestResult(new ServiceException(e));
    }
    // 此处才会调用微信统一下单接口,代码可以参考我的另一篇博客微信h5支付     return restResult;
    }
private void getopenId(String code){    String host = "https://api.weixin.qq.com";    String path = "/sns/oauth2/access_token";    Map<String, String> headers = new HashMap<>();    Map<String, String> querys = new HashMap<>();    querys.put("appid","");   //公众号appid,可以是服务商appid,也可以是子商户sub_appid    querys.put("secret","");  //和上面公众号appid对应的公众号的appKey    querys.put("code",code);    querys.put("grant_type","authorization_code");    String result = null;    try{        HttpResponse response = HttpUtils.doGet(host,path,"",headers,querys);           HttpEntity entity = response.getEntity();        if(entity != null){            result = EntityUtils.toString(entity,"UTF-8");            System.out.println(result);        }        JSONObject jsonObject = JSON.parseObject(result);     //这一步就可以获取到openid了,接下来你需要保存下来,在调用微信统一下单接口时这个参数是必传的        String openid = String.valueOf(jsonObject.get("openid"));        // TODO 保存openid,可以存session,也可以放缓存,甚至可以放数据库,随你一 一+    }catch (Exception e){        logger.info("oh !!! 获取openid失败");        throw new ServiceException("获取openid失败" + e.getMessage());    }}

  这里主要是通过上一步获取到的code,通过http请求的方式调用微信后台接口获取一个特殊的网页授权access_token,从中获取到openid,详见微信网页授权。关于HttpUtils这个网上有很多的资源。获取到openid后你需要先保存起来(为什么,因为作用域的问题),然后再去调用微信统一下单接口,生成预订单,然后将相关参数返回给前端,由前端来发起支付请求,调起微信支付,这部分可以参考微信内H5调起支付

  以上两步实际执行过程中是调来调去,中间经过了多次前后端交互,但是都是对用户无感的。

3. 遇到问题

3.1 点击支付之后,没反应

  这种问题其实不太好排查,因为是在手机端,不能f12(你懂的),后来是通过一堆alert将信息打印出来,才找到了问题。直接说结果吧,是由于WeixinJSBridge这个微信浏览器的内置对象还未加载完成,导致其invoke方法不能调用,自然就不能调起微信支付了。解决的办法就是搞了一个定时器,通过typeof window.WeixinJSBridge != "undefined"来判断WeixinJSBridge是否加载进来,加载好了再调微信支付,代码如下:

var test = setInterval(function(){
            if (typeof window.WeixinJSBridge != "undefined"){
                WeixinJSBridge.invoke(
            ‘getBrandWCPayRequest‘, {
              "appId":json.appId,
              "timeStamp":json.timeStamp,
              "nonceStr":json.nonceStr,
              "package":json.package,
              "signType":json.signType,
              "paySign":json.paySign
            },
            function (resp) {
              if (resp.err_msg === ‘get_brand_wcpay_request:ok‘) {
                Toast(‘微信支付成功‘)
                        _this.$router.go(-2);
                  } else if (resp.err_msg === ‘get_brand_wcpay_request:cancel‘) {
                    Toast(‘用户取消支付‘)
                            _this.$router.go(-1);
                  } else if (resp.err_msg === ‘get_brand_wcpay_request:fail‘) {
                    Toast(‘网络异常,请重试‘)
                            _this.$router.go(-1);
                  }
                }
              );
                clearInterval(test)
            }
        }, 100)  

3.2 下单账号与支付账号不一致,请核实后再支付怎么解决?

  原因:请求支付的 openid 和调用起支付时用户的 openid 不一致

  解决办法:传入的 openid 可以实时获取,获取支付用户的 openid 和调用微信统一下单接口时传的 openid 需要保证一致,不一样则会在微信支付界面出现上面的错误提示。

3.3 微信公众号支付出现:“当前页面的URL未注册”

  点击支付按钮出现“当前页面的URL未注册”的提示,这是由于未在商户平台中设置支付授权目录导致的。登录微信商户平台-产品中心-开发配置,配置支付授权路径。

3.4 {"errMsg":"chooseWXPay:fail"}

  出现这个问题目前发现有两个原因可能导致:

  1. 未设置授权回调域名,需要在开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。

  2. 是否这个时候还在pc端的微信开发者工具上测试,有时这也会导致这个问题,那就想办法在手机上测试吧。

3.5 get_brand_wcpay_request:fail

  错误如下,这个报错信息代表调起支付失败,原因同3.3。

4. 总结

  因为之前有h5对接的经验,所以调用统一下单接口是使用的之前代码(部分参数需要修改),主要是获取openid和配置域名,整个过程出的问题大部分还是自己去找的,微信文档中关于这方面的并不多,其实写的问题并不代表全部,但是整个过程都是自己一点一点做的。最后附上一张成功调起支付的图。最后祝大家国庆节快乐。

5 参考文献

微信支付getBrandWCPayRequest和wx.chooseWXPay有何区别

深究WeixinJSBridge未定义之因

微信公众号支付

原文地址:https://www.cnblogs.com/volcano-liu/p/9683327.html

时间: 2024-10-24 09:38:56

微信公众号支付踩坑记的相关文章

vue项目使用微信公众号支付总结及遇到的坑

微信公众号支付 1. 使用jssdk调用微信支付,具体查看开发文档: 使用的vuex,在mutations中 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 wechatPay (state, data) {     state.payObject = data     console.log('微信支付开始请求')     if (wechat) {      wx.chooseWXPay({       tim

微信公众号支付开发全过程 --JAVA

按照惯例,开头总得写点感想 ------------------------------------------------------------------ 业务流程 这个微信官网说的还是很详细的,还配了图.我还要再说一遍. 用户点击一个支付按钮-->{后台一大推处理}-->用户看到了一个输入密码的界面,包含金额等一些信息-->用户输入密码后出来一个支付成功的页面(这部分流程都是微信自己完成的,我们什么都不用做)-->返回系统自己的页面(总不能让用户一直看着一个支付完成的页面吧

vue项目使用微信公众号支付总结

微信公众号支付 1. 使用jssdk调用微信支付,具体查看开发文档: 使用的vuex,在mutations中 wechatPay (state, data) { state.payObject = data console.log('微信支付开始请求') if (wechat) { wx.chooseWXPay({ timestamp: state.payObject.timeStamp, // 支付签名时间戳 nonceStr: state.payObject.nonceStr, // 支付签

2017-9月微信公众号支付-Java详解

微信支付源代码 在此之前,先C麻瓜藤N遍,MD官方文档一半正确一半错误.言归正传, 微信支付整体流程:微信授权登录商户的公众号--微信支付的公众号配置--统一下单--微信js调起支付页面--输入密码支付--支付成功,异步回调URL处理商户的相应业务 一.业务场景: 先看一下支付的业务场景:用户使用微信登录商户页面,点击支付按钮,调起微信支付,选择付款卡号,输入密码,完成支付,如图: 场景十分简单,不过步骤比较多,稍不注意就掉坑里了. 二.微信公众号支付的配置准备: 1)调用公众号支付,首先你得有

使用开源库MAGICODES.WECHAT.SDK进行微信公众号支付开发

概要 博客使用Word发博,发布后,排版会出现很多问题,敬请谅解.可加群获取原始文档. 本篇主要讲解微信支付的开发流程,相关业务基于MAGICODES.WECHAT.SDK实现.通过本篇教程,您可以很方便的快速完成微信公众号支付的开发. 关于Magicodes.WeChat.SDK MAGICODES.WECHAT.SDK为心莱团队封装的轻量级微信SDK,现已全部开源,开源库地址为:https://github.com/xin-lai/Magicodes.WeChat.SDK 更多介绍,请关注后

微信公众号支付 js api java版本

说起来.微信支付真是一堆坑. 居然官网都没有java版本的完整代码. 就算是php版本的.还都有错误.且前后各种版本.各种文档一大堆....不停的误导开发人员. 花了一天半时间.总算实现了微信公众号支付.和pc端的微信扫码支付.其他不说了.直接给思路 本人做的是微信V3版本的微信支付.微信的官方文档中.提供的demo 只有一些工具类.这些类还是很有作用的. https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmp

微信公众号支付总结

微信公众号支付总结大致可以分为三步, 第一步获取用户授权,第二步调用统一下单接口获取预支付id,第三步H5调起微信支付的内置JS进行支付. 注意: 不得不提的是,每个公众号(公众平台),每一个APP(开放平台), 如果要进行微信支付得单独进行开通微信支付功能.开通成功后会为每一个公众号,APP 分配一个商户号.最开始没有搞清楚这层关系,导致出现类似"appid与商户号没有关联",授权时没有"scope 权限"这样的问题. 获取用户授权 String wxaccess

微信公众号支付H5调用支付详解

最近项目需要微信支付,然后看了下微信公众号支付,,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验. 一.配置公众号微信支付 需要我们配置微信公众号支付地址和测试白名单. 比如:支付JS页面的地址为 http://www.xxx.com/shop/pay/ 那此处配置www.xxx.com/shop/pay/ 二.开发流程 借用微信公众号支付api(地址 http://pay.weixin.qq.com/wiki/do

ASP.NET MVC 微信公众号支付,微信公众平台配置

微信公众号支付,首先要登录微信公众号进行配置: 第一步:配置网页授权域名 点击上图的修改则出现下面截图:进行修改(配置)网页授权的域名 第二步:配置支付授权目录 注意:支付授权目录的配置: 假设域名为:www.linjie.com 1.如果支付的页面在网站的根目录下,则配置格式为: http://域名/    例子:http://www.linjie.com/ 2.如果支付页面在网站的某个文件夹下,需要精确到文件夹:配置格式为:http://域名/文件夹名称/   例子支付页面在order文件下