手撕微信H5支付遇到的坑


最近“手撕”一词很火,加上最近在做微信H5支付遇到各种坑,故以此为题,书写微信支付的坑,预祝后来同仁饶坑而行,或者早日出坑。


一、准备工作
1.申请各种appid:本人项目中遇到的场景是在《app端》的《H5》中完成《公众号的微信支付》,加《》的意思是需要你注意了。所以我的appid有3个: 应用的appid即app端的,Web端的 appid即H5用的,及微信公共号用的。 重点:商户号有两个 分别对应了 微信支付商户号和微信公众号支付商户号,具体为啥这样,也许只有微信知道。

2.绑定appid到开放平台账号下,这样就能拿到在不同appid下对应的统一唯一标识unionid。而不同appid 获取到的 openid 有不相同,所以才有了unionid。

3.详细填写开放平台的开发配置,重点:授权回调域,api_key。应用的在开放平台,公众号的在平台。

二、填坑经历:
坑1:由于本人是接的之前项目,之前已经做了微信的授权登录与二次分享。所以我做支付的时候直接就用了,之前通过code换取得用户信息中的opneid。导致微信支付的统一下单失败。分析原因:是因为之前获取openid 是通过 web的appid获取的,这里应该使用公众号appid获取 openid作为统一下单接口中的openid参数。接下来的思路是原来的接口中替换appid和可以获取opnenid。
坑2:上面通过oauth2的方法获取openid,需要在请求中传入wechat_redirect回调的地址,这个地址需要在公众平台的 授权回调域中做配置,但是该配置只能指定到域名。所以重点:本人项目中的回调必须指定到端口,所以该回调可能会出现跨域的问题。所以接下来要做的是解决跨域问题。最佳策略请百度。本人采用的方法是写死静态回调页面,获取code,再通过code换取openid.
坑3:下单成功后,返回给前端下单成功信息,但是前端仍然无法调起微信支付。然后根据前端的返回提示修改错误,指导报签名错误。
解决办法:a.返回前端的签名自己在微信的签名检查工具中做检查 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1。确保自己的签名无误。推荐使用微信的官方加签名的方式及xml和map的转换方法。
b.保证 a无误的条件下,判断前端是否正确传参,前端 的返回信息务必原样提示微信端的返回信息,不要做自定义处理,方便根据返回信息调试错误。
c.仍让签名失败。本人采取的方式是,后端加签前的key与微信H5调起支付的参数大小写一致,并重置api_key。终于迎来微信的笑脸。

至于如何下订单,如何处理回调网上有不少例子,在此就不在列举,下单接口中报各种不匹配,那就肯定是不匹配,所以务必梳理自己公司的 appid及类型,商户号之间的正确对应的关系,并明确自己到底是使用那个appid,api_key及商户id.

补充 ———————————————————————————————————————————
一· 按照领导要求有做了app及H5微信外部的微信支付。结果发现:微信的支付至少有三种方式。 1.app的微信支付 2.微信的公众号H5支付。3.非微信的web浏览器支付。以上三种方式均需要调用微信的统一下单接口,其中需要的参数都大同小异常。支付成功后的回调接口基本没有区别,都是在回调中处理 自己的业务,并返回给微信回调成功响应。
二.比较:
1.统一下单接口中的body 字段格式需要严格按照微信要求的格式处理,对于中文的字符body,在发请求请 对字符串做处理编码处理,例:
String strResult = HttpUtil.executePost(null,WXPayConstants.ORDER_URL, new String(orderXml.toString().getBytes(), “ISO-8859-1”));
2.做公众号的H5支付,当trade_type=jsapi 时候 需要获取公众号对应的用户openid
3.公众号H5支付及app支付调用统一下单接口后,需要对返回结果处理,并在此加签给前端。例如:

 String strResult = HttpUtil.executePost(null, WXPayConstants.ORDER_URL, new   String(orderXml.toString().getBytes(), "ISO-8859-1"));
                LOG.info("wxpay/creatorder  strResult:" + strResult.toString());
                try {
                    /**统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。
                     * 参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay**/
                    Map<String, String> map = WXPayUtil.xmlToMap(strResult);
                    SortedMap<String, String> reMap = new TreeMap<String, String>();
                    reMap.put("appid", WXPayConstants.APP_APP_ID);
                    reMap.put("partnerid", WXPayConstants.APP_MCH_ID);
                    reMap.put("prepayid", map.get("prepay_id"));
                    reMap.put("package", "Sign=WXPay");
                    reMap.put("noncestr", WXPayUtil.generateNonceStr());
                    //本来生成的时间戳是13位,但是ios必须是10位,所以截取了一下
                    reMap.put("timestamp", String.valueOf(System.currentTimeMillis()).toString().substring(0, 10));
                    reMap.put("sign", WXPayUtil.generateSignature(reMap, WXPayConstants.APP_API_KEY));

而非微信H5浏览器支付,则不需要在此加签名,直接返回前端下单成功后返回结果中的跳转mweb_rul,前端还需要再该URL上添加 支付成功后 的redirect_url,该rediret_url需要做uriencode,确保在非腾讯浏览器正常打开。因为前端无法获取支付成功或者失败,我的处理思路是:在该地址访问订单详情接口给前端展示,订单详情接口中有标识该次支付是否成功的标识,前端因此就可以获取支付是否成功失败。(问题:若微信的回调失败或者慢,会导致该标识不准确,具体解决方案还待考虑)

猜你喜欢

转载自blog.csdn.net/qq_28014495/article/details/78812570