• 微信、支付宝个人收款的一种实现思路


    原文地址:https://juejin.im/entry/5aa4c36df265da2397067a81


    题目里说的个人收款指的不是普通的扫个码,而是说那种可以支持回调的,例如网上商城支付之后,商城可以知道支付状态并且自动修改订单的状态为“已支付”。这种支付的形式,无论是微信、支付宝还是银联,目前都是不对个人开放的,必须有企业资质才能申请。但是对于很多开发者而言,有时候就是一个小小的验证性应用,想要拥有支付功能,而自己又没有企业资质,自然没法申请到微信支付宝这种接口,甚至连第三方的聚合支付(Ping++)也是无法申请的。本文就介绍一种利用个人支付宝(微信也是可以的)自己实现支付功能的思路,成本是一部旧的安卓手机,其他的都是完全免费的,配合支付宝的收款码(提现免费),可以做到零费率

    一、基本思路

    这个方案的基本思路是非常简单的,跟之前大家常用的用爬虫爬取网页账单数据类似,但是这里我们用的是手机App。相对来说,截取手机App的推送消息更为简单,不需要应为微信支付宝的各种反爬措施;但是缺点是能够获取到的信息较少,没有诸如流水号、付款人之类的信息,只有一个金额。

    所以,我们的思路就是:

    1. 创建一个订单,将二维码(定额或者非定额都可以)展示给用户
    2. 用户支付后,商家手机App上收到支付宝的付款推送
    3. 安卓App截取支付宝的付款推送,然后将付款信息发送给服务器
    4. 服务器根据付款金额,确定到底是哪一笔订单,然后将该订单标记为“已付款”,然后根据需要进行回调通知之类的操作。

    二、关键问题及其解决方案

    这个方案里的关键问题有以下几个:

    1.支付宝App的通知截取

    这个问题其实网上已经有很多的解决方案了,其利用的是Android中的NotificationListenerService这个类,通过注册这个Listener,可以在推送通知弹出来的时候,获取到其发送的App、标题、内容等信息。我们最关心的就是App和推送内容。

    判断发送App的包为支付宝的包,然后再从推送的内容中获取到具体的内容,即可得到付款金额。

    示例代码如下:

    1. public class AlipayNotificationListenerService extends NotificationListenerService {
    2. public AlipayNotificationListenerService() {
    3. }
    4. @Override
    5. public void onNotificationPosted(StatusBarNotification sbn) {
    6. // 这里可以拿到包名,可以按照需要判断。
    7. String packageName = sbn.getPackageName();
    8. Notification notification = sbn.getNotification();
    9. if (notification == null) {
    10. return;
    11. }
    12. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    13. Log.e("SevenNLS","in 1");
    14. Bundle extras = notification.extras;
    15. if (extras != null) {
    16. // 这里是具体的title和content,可以从中提取金额
    17. String title = extras.getString(Notification.EXTRA_TITLE, "");
    18. String content = extras.getString(Notification.EXTRA_TEXT, "");
    19. Log.d("Zachary", "title:" + title + " content:" + content);
    20. }
    21. }
    22. }
    23. @Override
    24. public void onListenerConnected()
    25. {
    26. Log.e("Zachary","connected");
    27. }
    28. }

    当然,为了让这个App能够顺利进行,还要给它获取通知的权限,保证它不被清理等等,需要做一些相应的保护措施。

    2.订单的确定

    刚才我们说过,服务器收到App发来的收款信息之后,还需要找到对应的订单。这一步是相对比较难的一步,因为我们知道相同金额的订单可能有很多,到底哪一个才是刚刚支付的订单呢?

    这里,我们可以再详细思考一下,其实这个订单不仅仅是由这个金额确定的,而是一个多元组共同确定的。最简单的一种实现方式就是 (订单金额-支付状态)。通过这个二元组可以确定一个订单。其含义是,如果这个订单已经支付过了,那么我在查找订单的时候,就可以不用理会它了,我只需要查找(指定金额-未支付)的订单就可以了。

    这样可以基本解决这个问题。但是,我们考虑到除了正常支付外,还有可能会有另外一些情况。比如用户创建了订单之后,突然不想支付了,没有进行接下来的操作。或者说,有人恶意在网站上创建了大量的订单并且不支付。 这样的后果是,这些订单的状态永远都是未支付,当你想要继续创建订单的时候,就会受到限制,不能创建跟这些订单相同金额的订单,否则你的系统将无法分辨到底是哪一笔订单被支付了。

    为了应对这种情况,我们想到其实很多的支付都是有时间限制的,也就是说,订单是有有效期的,一旦过了有效期,订单就不能被支付了。所以我们也可以给订单加一个有效时间的限制,比如5分钟,一旦五分钟内没有被支付,就认为这个订单已经失效了。这时,订单的确定方式就变成了一个三元组(订单金额-支付状态-是否过期)。查找的时候,只需要查找(指定金额-未支付-未过期)的订单就可以了。也就是说,任意一个订单,最多只会占用这个金额5分钟,一旦超过五分钟,不管支付与否,你都可以继续创建相同金额的订单了。

    但是这样我们还是觉得不满意,特别是对于某些支付金额相对单一的情况,可能每次都需要创建相同金额的订单,这样的话,再最坏情况下我们只能每隔五分钟处理一个订单,这个效率可以说是非常低效了。

    在这里,我们提出了一种trade-off的解决方法。一般的正常支付是不会使用这种方式的,也难以接受,但是对于我们来说,为了避免企业资质的认证和手续费,在一定程度上是可以接受的。

    这种方式就是,当目前系统中已经有了某一金额的订单的时候,如果我们要继续创建相同金额的订单,那么我们就在指定金额上进行上下浮动,比如下浮一分钱,这样金额就可以和之前的订单区分开来,避免出现不能同时支付的情况。这样,虽然我们在高并发情况下可能会有一定的损失(同时支付的人越多,差距越大),但是满足了我们的高并发要求。

    友情提示:如果金额发生浮动,可以告诉用户这是随机立减,一定程度上可以避免定价和实际支付金额的差距带来的问题。(这种情况下就只能下浮,不能上浮,不然就变成随机立加了)。

    三、总结

    总体上来说,我认为这种方案对于普通的个人用户来说,是一种可以接受的方案。其优缺点总结如下:

    优点:

    1. 不需要企业资质
    2. 没有手续费
    3. 不对支付宝进行任何操作,没有被支付宝进行风控的风险

    缺点:

    1. 需要有一部手机一直运行,且要求网络条件良好,否则会丢失支付数据(可以有人工解决方案)
    2. 高并发时,订单金额会产生浮动
    3. 如果金额浮动策略不合理,并且被人探索出规律,可能造成财产损失!!(例如短时间内创建大量订单,这样订单价格会不断下降,需要针对这种情况做出防范)

    参考:
    PaysApi: www.paysapi.com

  • 相关阅读:
    usb 安装系统
    跨站请求伪造攻击的基本原理与防范
    解决hexo神烦的DTraceProviderBindings MODULE_NOT_FOUND
    我知道
    MAC 重置MySQL root 密码
    线性变换与独立观察的期望和方差
    最小二乘法
    卡方检验中自由度的计算
    关于置信水平,求区间的简便算法
    独立观察与线性变换方差 均值计算
  • 原文地址:https://www.cnblogs.com/jpfss/p/9764775.html
Copyright © 2020-2023  润新知