1. 程式人生 > >微信、支付寶個人收款的一種實現思路

微信、支付寶個人收款的一種實現思路

原文地址:https://juejin.im/entry/5aa4c36df265da2397067a81題目裡說的個人收款指的不是普通的掃個碼,而是說那種可以支援回撥的,例如網上商城支付之後,商城可以知道支付狀態並且自動修改訂單的狀態為“已支付”。這種支付的形式,無論是微信、支付寶還是銀聯,目前都是不對個人開放的,必須有企業資質才能申請。但是對於很多開發者而言,有時候就是一個小小的驗證性應用,想要擁有支付功能,而自己又沒有企業資質,自然沒法申請到微信支付寶這種介面,甚至連第三方的聚合支付(Ping++)也是無法申請的。本文就介紹一種利用個人支付寶(微信也是可以的)自己實現支付功能的思路,成本是一部舊的安卓手機,其他的都是完全免費的,配合支付寶的收款碼(提現免費),可以做到零費率

一、基本思路

這個方案的基本思路是非常簡單的,跟之前大家常用的用爬蟲爬取網頁賬單資料類似,但是這裡我們用的是手機App。相對來說,擷取手機App的推送訊息更為簡單,不需要應為微信支付寶的各種反爬措施;但是缺點是能夠獲取到的資訊較少,沒有諸如流水號、付款人之類的資訊,只有一個金額。

所以,我們的思路就是:

  1. 建立一個訂單,將二維碼(定額或者非定額都可以)展示給使用者
  2. 使用者支付後,商家手機App上收到支付寶的付款推送
  3. 安卓App擷取支付寶的付款推送,然後將付款資訊傳送給伺服器
  4. 伺服器根據付款金額,確定到底是哪一筆訂單,然後將該訂單標記為“已付款”,然後根據需要進行回撥通知之類的操作。

二、關鍵問題及其解決方案

這個方案裡的關鍵問題有以下幾個:

1.支付寶App的通知擷取

這個問題其實網上已經有很多的解決方案了,其利用的是Android中的NotificationListenerService這個類,通過註冊這個Listener,可以在推送通知彈出來的時候,獲取到其傳送的App、標題、內容等資訊。我們最關心的就是App和推送內容。

判斷髮送App的包為支付寶的包,然後再從推送的內容中獲取到具體的內容,即可得到付款金額。

示例程式碼如下:

public class AlipayNotificationListenerService extends NotificationListenerService {
    public AlipayNotificationListenerService() {
    }

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        // 這裡可以拿到包名,可以按照需要判斷。
        String packageName = sbn.getPackageName();
        Notification notification = sbn.getNotification();
        if (notification == null) {
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Log.e("SevenNLS","in 1");
            Bundle extras = notification.extras;

            if (extras != null) {
                // 這裡是具體的title和content,可以從中提取金額
                String title = extras.getString(Notification.EXTRA_TITLE, "");
                String content = extras.getString(Notification.EXTRA_TEXT, "");
                Log.d("Zachary", "title:" + title + "   content:" + content);
            }
        }
    }

    @Override
    public void onListenerConnected()
    {
        Log.e("Zachary","connected");
    }


}

當然,為了讓這個App能夠順利進行,還要給它獲取通知的許可權,保證它不被清理等等,需要做一些相應的保護措施。

2.訂單的確定

剛才我們說過,伺服器收到App發來的收款資訊之後,還需要找到對應的訂單。這一步是相對比較難的一步,因為我們知道相同金額的訂單可能有很多,到底哪一個才是剛剛支付的訂單呢?

這裡,我們可以再詳細思考一下,其實這個訂單不僅僅是由這個金額確定的,而是一個多元組共同確定的。最簡單的一種實現方式就是 (訂單金額-支付狀態)。通過這個二元組可以確定一個訂單。其含義是,如果這個訂單已經支付過了,那麼我在查詢訂單的時候,就可以不用理會它了,我只需要查詢(指定金額-未支付)的訂單就可以了。

這樣可以基本解決這個問題。但是,我們考慮到除了正常支付外,還有可能會有另外一些情況。比如使用者建立了訂單之後,突然不想支付了,沒有進行接下來的操作。或者說,有人惡意在網站上建立了大量的訂單並且不支付。 這樣的後果是,這些訂單的狀態永遠都是未支付

,當你想要繼續建立訂單的時候,就會受到限制,不能建立跟這些訂單相同金額的訂單,否則你的系統將無法分辨到底是哪一筆訂單被支付了。

為了應對這種情況,我們想到其實很多的支付都是有時間限制的,也就是說,訂單是有有效期的,一旦過了有效期,訂單就不能被支付了。所以我們也可以給訂單加一個有效時間的限制,比如5分鐘,一旦五分鐘內沒有被支付,就認為這個訂單已經失效了。這時,訂單的確定方式就變成了一個三元組(訂單金額-支付狀態-是否過期)。查詢的時候,只需要查詢(指定金額-未支付-未過期)的訂單就可以了。也就是說,任意一個訂單,最多隻會佔用這個金額5分鐘,一旦超過五分鐘,不管支付與否,你都可以繼續建立相同金額的訂單了。

但是這樣我們還是覺得不滿意,特別是對於某些支付金額相對單一的情況,可能每次都需要建立相同金額的訂單,這樣的話,再最壞情況下我們只能每隔五分鐘處理一個訂單,這個效率可以說是非常低效了。

在這裡,我們提出了一種trade-off的解決方法。一般的正常支付是不會使用這種方式的,也難以接受,但是對於我們來說,為了避免企業資質的認證和手續費,在一定程度上是可以接受的。

這種方式就是,當目前系統中已經有了某一金額的訂單的時候,如果我們要繼續建立相同金額的訂單,那麼我們就在指定金額上進行上下浮動,比如下浮一分錢,這樣金額就可以和之前的訂單區分開來,避免出現不能同時支付的情況。這樣,雖然我們在高併發情況下可能會有一定的損失(同時支付的人越多,差距越大),但是滿足了我們的高併發要求。

友情提示:如果金額發生浮動,可以告訴使用者這是隨機立減,一定程度上可以避免定價和實際支付金額的差距帶來的問題。(這種情況下就只能下浮,不能上浮,不然就變成隨機立加了)。

三、總結

總體上來說,我認為這種方案對於普通的個人使用者來說,是一種可以接受的方案。其優缺點總結如下:

優點:

  1. 不需要企業資質
  2. 沒有手續費
  3. 不對支付寶進行任何操作,沒有被支付寶進行風控的風險

缺點:

  1. 需要有一部手機一直執行,且要求網路條件良好,否則會丟失支付資料(可以有人工解決方案)
  2. 高併發時,訂單金額會產生浮動
  3. 如果金額浮動策略不合理,並且被人探索出規律,可能造成財產損失!!(例如短時間內建立大量訂單,這樣訂單價格會不斷下降,需要針對這種情況做出防範)