微信支付开发踩坑与吐槽
微信支付作为国内非常便捷的支付系统,自然有着很大的吸引力。然而,与之规模不相称的是,微信支付的开发是一个非常痛苦的过程。自己就面临着资料少且不全、文档不专业不具体的种种问题,甚至还有一些不为人知的隐秘 bug。本文将从最常用的微信支付渠道之一——微信公众号支付的开发讲起,抛砖引玉,总(tu)结(cao)开发中遇到的坑,以节约大家宝贵时间,避免重复踩坑。特别鸣谢:@yelo。
让人迷惑的 key,key,key
微信支付大概需要 4 种密钥(参考来源):
APPID
:对于公众号,就是公众号的“开发者ID(AppID)”微信支付商户号
:微信支付商户平台中获取,目前也可以在微信服务号后台的“微信支付”页面获取。API密钥
:在微信支付商户平台中获取。一定注意这个 API 密钥不是公众号的secret
。Appsecret
:就是公众号的“开发者密码(AppSecret)”
一个支付,弄这么多密钥,真的是让人头大。
不专业且不责任的文档与 API
公众号支付的文档有两处:微信网页 SDK 中的一个章节 和 微信支付文档。 这两处文档都有很多槽点:
- 这两处文档中的代码使用的前端支付接口不一样。虽然后面有了解到,微信网页 SDK 调用支付时,本质也是通过
WeixinJSBridge.invoke()
实现的,但是微信文档似乎没有对此做一个详尽的比较,真的是让人感到困惑与选择困难。 - 两处请求参数的 JSON 结构有一处不一致:
timeStamp
vstimestamp
。这一点可谓非常不专业。对比如下:
// 微信支付文档:公众号支付
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"wx2421b1c4370ec43b", //公众号名称,由商户传入
"timeStamp":"1395712654", //时间戳,自1970年以来的秒数
// ...省略
}
// 微信公众号网页 SDK 文档
wx.chooseWXPay({
timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
// ...省略
});
- 微信公众号网页 SDK 文档中只有支付成功的回调函数,并没有失败的。
坑人的“JSAPI 支付授权目录”
对于重前端的 SPA 应用,支付时有一个大坑:https://www.example.com/#/foo-path
和 https://www.example.com/?#/foo-path
并不是一个 URL,微信似乎会把前者当作 https://www.example.com/foo-path
。
举个例子,如果你在微信支付后台配置的“JSAPI 支付授权目录”为 https://www.example.com
,那么:
URL | 结果 |
---|---|
https://www.example.com/#/foo-path |
支付失败,配置的支付授权目录错误 |
https://www.example.com/?#/foo-path |
支付成功 |
也就是说,在 hashtag 之前,必须有一个问号(?),否则不会支付成功。
粗暴的解决方案,判断 URL 中是否含有问号,不含问号时添加一个:
private hackWechatPay() {
const url = window.location.href;
// 判断当前url是否存在?参数匹配符
if (!url.match(/\?#/)) {
location.replace(window.location.href.split('#')[0] + '?' + window.location.hash);
return;
}
// Reference: https://www.jianshu.com/p/1ace87d3c1fc
}
奇怪的沙箱模式与开发环境
开始开发的时候,以为微信支付的沙箱环境就是用于测试的环境。但是其实用处不大:
- 支付金额仅是固定的几个,比如
1.01
等等。 - 在自己的开发模式,即使可以签名成功,也会提示诸如“没有提供 out_trade_no“或者“调用支付JSAPI缺少参数:total_fee”之类的驴唇不对马嘴的奇怪错误,前端代码无法获取到支付成功的回调。
- 即使沙箱模式,也必需使用生产环境绑定的域名,无法在本地测试。
- 前端开发方面,即使用官方的“微信开发者工具”,也没有办法进行模拟支付(生产环境也不行),给调试造成了巨大不便。个人在生产环境调试方法是,判断 URL 中是否有某一个特殊的 flag,如果有的话,就加载诸如 eruda 或者 vconsole 这样的调试工具。
一个小总结就是,不要使用沙箱模式进行开发,没有必要,完全浪费时间。直接线上环境肉测吧。什么自动化测试,TDD,见鬼去吧。
结语
目前认为,微信公众号支付的开发最佳实践是:
- 使用生产环境进行测试,如果生产环境不能用来测试,那么就需要额外注册一个支持微信支付的服务号进行测试。并且,生产环境尽量要加入允许调出调试工具的 URL param flag,随时调试(参考上一节第四点)。
- 服务端进行支付验证时,注意不要用
cash_fee
,这个是使用优惠券后的实际支付价格。订单价格验证要用total_fee
。 - 官方文档看看就行了,不如社区的踩坑经历有价值。但是注意踩坑经历的时效性。
本文目的在于节约大家的宝贵开发时间,同时指出微信团队的可改进之处。目前微信支付的开发体验,真的是让人无法更失望。从微信支付系统的开发到上线,简直是像下图一样的过程:
(来源 @jaceju)
作为母公司两万多亿港元市值的企业,拿出一小部分资源优化这个核心业务,总比 PayPal(近 $1,000 亿市值) 和 Stripe 要容易很多。大家可以对比下这些支付系统的文档和开发体验,高下立判。微信支付的文档水平,甚至不如国内某些支付创业公司。另外,服务端的 SDK,也基本是开发者们各自为战,重复造轮子。这不是能力问题,是态度问题。优化开发流程与体验,对腾讯(微信)和开发者还有商户是多赢的——提高项目上线速度、上线后的稳定性与支付成功率,对大家都是好事,何乐而不为呢?
(未完待续)
参考资料
- 微信支付的沙箱环境能否使用?https://github.com/Wechat-Group/weixin-java-tools/issues/668#issuecomment-409504376
- Stripe on GitHub:https://github.com/stripe
- PayPal SDKs: https://github.com/paypal?utf8=✓&q=sdk&type=&language=
- 微信支付小坑:http://kinoandworld.github.io/blog/2014/09/17/weixinpayforios/
- 谈谈那些年微信支付踩过的坑:https://www.ieclipse.cn/2017/05/24/Android/quickaf-wechat-pay/
- 一次痛苦又甜蜜的微信支付踩坑之旅:https://segmentfault.com/a/1190000013460422