记得上次接触微信支付是2016年底,那次也是我程序生涯中首次碰及支付业务,慌张谈不上但是懵逼怀疑时时都有。说起第三方登录或者支付,想必都清楚是直接调用人家现成的API,完全没有开发成本和技术含量。但是我想说:如果你没有过一次从零开发并维护过一个完整支付模块的话,我相信有很多坑对你来说都是黑盒的,也许现在的公司或多或少都涵盖了支付业务,可能被早先的老程序员们已经维护的差不多完美了,完全是可以当成模板功能来使用,新手只需复制大体功能架子填充支付后的业务逻辑即可。
好了,切入正题吧。为什么突然在各位前辈面前摆上这么一篇没有任何技术含量的文章呢?因为好久没有在博客园发布过文章了,刚刚瞻仰完各位大佬分享的东西后心里很空虚。其次是主要原因,由于前几天休假刚回来就被刚刚入职的哥们拉住绕了一会儿,说这俩天测试人员反应充一次钱之后会看到好几条充值记录并且是偶现的,而且相应的游戏币也累加了很多次等等,然后还有一个更坑的现象就是照着微信开发文档调用接口,唤醒微信支付的组件开始调用预支付(统一下单)接口时抛签名错误的异常,竟然调不通(声明:签名方式已经是确保无误的)。。。真的,听他一说还真回忆起当年那个手忙脚乱的自己,在开发过程中各种懵逼、各种怀疑人生。所以今天就把这些踩坑经历分享一下,仅献给圈里刚刚接触或要开始接手支付业务的朋友,希望各位在铸造支付模块时能够一马平川。
1、登录微信商户平台,注意是商户平台不是开放平台,根据业务场景选择适合自己的支付类型,进入之后就可以看看具体的API列表,除此之外还提供了业务场景举例、业务流程时序图等非常清晰。提醒一点微信还提供了专门的demo压缩包,里面包含了工具类WXPayUtil建议下载,因为相信你能用到,是百分百能用到。
2、移动端唤起微信支付的组件,首先发起开始支付的动作,服务端就会相应的调用预支付(统一下单)接口https://api.mch.weixin.qq.com/pay/unifiedorder,注意该过程需要对参数进行签名,然后将带有签名字段的参数作为接口形参,过程比较繁琐建议封装一下,后续的操作还有会用到的,最后拿到微信服务器返回的结果后解析出移动端需要的参数,记得签名后返给前端。好了部分源码可以参考一下:
3、移动端拿到支付参数后就会真正调起支付操作,这时后端只需做一个供微信回调的接口,该接口的作用主要是接受每次支付的支付结果。注意:该回调地址需要在发起预支付接口时务必告诉微信服务器,而且还要保证能够畅通无阻。当完成一笔支付操作后,微信服务器就立刻会调用你提供的自定义回调接口告诉你支付结果,你只需完成支付成功后的业务逻辑,即视为本次支付过程结束。
4、当然,微信也专门提供了查询某笔支付订单的支付结果的接口https://api.mch.weixin.qq.com/pay/orderquery,详情自行查询。
OK,到这儿整个支付业务算是真正跑通了,勉强画条暂时的分割线吧。
这个问题确实对于很多新手来说是狠TM扯淡的,调不通还老提示签名错误可能是因为:http请求的参数列表中body那个字段你传的是中文,并且微信开发文档中的案例模板也是中文。
解决方案:只需将最终发送的参数列表进行编码处理即可,但是你也可以全部传入英文。
这个问题就有点考验你写接口的质量了,出现仅支付一次产生多条支付明细记录的情况,首先是因为你没有做好在成功拿到微信回调结果后及时对当前支付记录做好重复处理的逻辑,因为那哥们儿发起一笔支付请求后在成功拿到支付结果没有告诉微信支付成功,所以微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功,通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒。所以不断处理同一笔支付订单。其次就是没有考虑并发的情况,需要对拿到的回调结果做线程安全的处理,可以有俩种方案:第一种就是在数据库层面上做限制,设置联合主键将重复操作的支付记录数据挡在外面不允许插入数据库;第二种是在业务层加锁,在处理每笔支付结果时判断是否已经处理过了,如果处理过就忽略当前回调结果否则正常处理。提醒一点:不要直接在方法上直接添加synchronized,还有在加锁的时候尽量将锁的粒度控制到最小,否则会影响接口的性能。(参考:http://www.cnblogs.com/1315925303zxz/p/7561236.html)