今天在浏览V2EX的时候,看到了一个很搞笑的帖子,楼主在平台上开了一个可以把支付宝和微信的支付码合二为一的项目,由于楼主在项目中默认填写了自己的支付宝和微信信息,导致项目分叉之后,很多人都没有修改这些信息,特别是一些用于恶意目的的分叉分支更是没有修改,结果很多人通过扫描这些生成的二维码上当受骗,最终导致楼主的微信被封号收款,连红包都收不到。
虽然故事本身有些可笑,但是自己动手把支付宝和微信的付款码合二为一的想法还是很有意思的,在网上搜了一下,发现合并付款码的方法大致有两种。
一类是以芝麻支付为代表的第三方解决方案。这些第三方解决方案需要用户分别上传支付宝和微信的支付码,然后返回一个新的聚合支付码。据查阅到的信息,之前芝麻支付是免费的,现在收费4.5元。考虑到支付码涉及到资金流转,交给第三方不安全;而这么简单的事情还要收费,有点像“故意利用技术壁垒”。作为一个喜欢自己动手的人,我实在是受不了。
第二类就是上面OP为代表的开源方案。这类方案对用户的动手能力要求比较高,需要有一台可以公开访问的服务器来执行判断脚本。这个套路里,也分流派。一派是PHP等为代表的方案,需要上面的服务器能够执行PHP等脚本。这种方案不适合静态页面博客,所以使用范围比较有限。另一派是带有静态HTML和CSS的方案。这种方案适用范围要广泛得多。
本文介绍一种以静态HTML为基础,辅以CSS,生成聚合支付代码的解决方案。
二维码支付的真相
其实二维码只是一种编码方式,将信息编码到方形二维码的形状中,但二维码协议定义了很多冗余,比如抗干扰、防损坏等,但实际上二维码只编码了部分信息。
当我们使用微信、支付宝等移动应用扫描二维码时,这些应用的行为取决于二维码中编码的信息。应用会先解码二维码,然后根据这些信息采取相应的行动。通过二维码接收付款时,二维码至少应包含要转账的目标人的 uid 以及(如有必要)所需的金额。
开源中国工具集中包含了二维码的解码工具,利用这些工具,我们可以读取二维码中编码的信息。以下是从我的支付宝、微信、钱包的支付码中读取到的信息(关键信息已隐藏)。
可以看出,无论支付宝、微信还是钱包,支付背后的二维码其实就是一个URL。但实际测试显示,只有支付宝可以从URL直接发起支付动作;微信和钱包应该在这里做出额外的判断保护,防止用户误点击链接进行支付。
因此,解决方案变为:
显然,这个判断动作必须发生在一个可以公开访问的服务器上。因此,问题就变成了如何让App在扫描到对应的二维码后,能够访问到公共服务器上的某个位置;以及如何判断用户使用哪个App扫描该位置的聚合码并返回相应的内容。前一个问题很好解决,因为这是App扫描二维码后的默认动作。因此我们重点解决后者的问题。
HTTP 协议消息头中包含了所谓的用户代理(User ,简称 UA),UA 其实就是用户使用的浏览器,因此可以想象当用户使用不同的 APP 扫描二维码访问公共服务器时,HTTP 消息头中包含的 UA 是不同的,我们可以通过这个来判断用户使用的 APP。
为此我们需要检测支付宝、微信、钱包的UA中哪些内容可以作为特征字段,详细做法会在后续文章中讲解,这里给出结论:
在HTML中,我们可以通过..(//i)来判断UA是否包含该特征字符串,据此我们有:
1
2
3
4
5
6
7
8
9

if (navigator.userAgent.match(/Alipay/i)) {
// 返回支付宝链接
} else if (navigator.userAgent.match(/MicroMessenger\//i)) {
// 返回微信链接对应的二维码
} else if (navigator.userAgent.match(/QQ\//i)) {
// 返回 QQ 钱包链接对应的二维码
} else {
// 不支持的 App
}
在线生成二维码
由于聚合码需要在微信或者钱包扫描时返回对应链接对应的二维码,所以我们要么把对应的二维码保存下来,要么想办法在线生成返回给用户。在线生成二维码有两种方式,一种是使用 等工具中的接口,直接由用户浏览器(手机APP)生成二维码,一种就是调用现成的接口,这里我们就是通过调用现成的接口来生成二维码。
这里我们使用百度云API来生成二维码。
1
https://pan.baidu.com/share/qrcode?w=150&h=150&url=Liam%20loves%20Sophia!
返回的二维码中隐藏的信息是:
1
Liam loves Sophia!
至此,解决方案的主要思想已经说明;完整代码可用。
使用时需先获取支付宝、微信、钱包的二维码,再获取对应的链接,三个APP的操作路径为:
将上面保存的二维码上传到开源中国,获取二维码后面的链接。然后在.html 的配置中填写这些链接。最后把HTML文档上传到公共服务器就行了。给出的二维码如下,可以扫描测试一下——当然,最后能转账就更好了!
致谢
该项目原作者应为孟坤,感谢!