Payment:支付的回調統一處理

有20天沒有更新了,主要原因有二:其一這期間對自己的職業規劃做了一些調整;其二生了一場小病。所以大家一定要保重身體,平時得多鍛鍊鍛鍊了。

根據大家反饋,大家對 Payment 還是很認同,這讓我很開心。五一花了兩天時間把招商一網通集成進來了。希望能夠幫助到更多的人。


Payment使用文檔https://helei112g.github.io/categories/payment-3/

項目GitHub地址https://github.com/helei112g/payment

言歸正傳,這篇拖了很久了,藉着五一假期的最後一天,搞定它!先上一個支付的一般流程圖。

image
圖片來源:支付寶

異步與同步

在我們完成支付後,要確認用戶是否真的支付了這筆錢,以及這筆錢支付的金額是否符合預期。怎麼知道這些事情呢?

用戶告訴我們?我們肯定不能確認是否真假。比較恰當的方式是,第三方(支付寶、微信、招商一網通等)收到用戶付款後,他來告訴我們。所以這裏就引出了通知這個概念。

通知的方式又有兩種:同步通知,異步通知。同步通知的概念存在於網站支付或者H5支付中,因爲只有在瀏覽器中纔可以通過url進行跳轉。那麼我們應該使用同步通知作爲支付成功的依據還是使用異步通知呢?

我的答案是:同步通知不做服務端的更新,可用於客戶端的顯示,異步收到通知時才做相關的更新處理。原因有三:

  1. 並不是所有的支付模塊都有同步通知這個概念;
  2. 同步通知的參數在url中,就算採用https協議,也存在更大被篡改的風險;
  3. 異步通知提供完整的失敗重發機制,更值得信耐。

異步通知處理

所以在 Payment 中只針對異步通知到達的數據進行了簽名相關處理。下面我們來看看代碼。

不管你是支付寶的異步通知,還是微信的異步通知或者招商一網通的異步通知,Payment 都提供了統一的異步處理接口,並且調用者完全不必去關心如何驗證簽名,如何覈實數據,只需要專注自己的業務邏輯即可。

回調使用了一個開發的小技巧:依賴注入,我先上代碼,後面稍微解釋下。

$callback = new TestNotify();

$type = 'ali_charge';// ali_charge wx_charge  cmb_charge

try {
    // 獲取第三方的原始數據,未進行簽名檢查,根據自己需要決定是否需要該步驟
    //$retData = Notify::getNotifyData($type, $config);

    $ret = Notify::run($type, $config, $callback);// 處理回調,內部進行了簽名檢查
} catch (PayException $e) {
    echo $e->errorMessage();
    exit;
}

return $ret;

回調 的代碼就這麼簡單,其中 Notify::getNotifyData($type, $config); 可以獲取到第三方的回調數據,sdk僅僅是解析成數組返回,沒有做簽名檢查,不能直接用來進行回調處理。

Notify::run($type, $config, $callback); 則是進行回調相關的處理,它返回的值,是需要返回給第三方支付機構的,第三方機構通過返回值來識別商戶是否正確處理了回調通知,並且以此來處理是否需要重發。

這裏的重點就是 $callback,注意看上面的代碼 $callback = new TestNotify();

大家的重點就是創建這個 TestNotify 這個類,我們就叫它:商戶回調業務處理類,名字大家隨便取,根據自己的需要。看一下我示例中 TestNotify.php 的內容

use Payment\Notify\PayNotifyInterface;
use Payment\Config;

/**
 * 客戶端需要繼承該接口,並實現這個方法,在其中實現對應的業務邏輯
 * Class TestNotify
 * anthor helei
 */
class TestNotify implements PayNotifyInterface
{
    public function notifyProcess(array $data)
    {
        $channel = $data['channel'];
        if ($channel === Config::ALI_CHARGE) {// 支付寶支付

        } elseif ($channel === Config::WX_CHARGE) {// 微信支付

        } elseif ($channel === Config::CMB_CHARGE) {// 招商支付

        } elseif ($channel === Config::CMB_BIND) {// 招商簽約

        } else {
            // 其它類型的通知
        }

        // 執行業務邏輯,成功後返回true
        return true;
    }
}

這裏的核心就是,客戶端創建的 商戶回調業務處理類 一定要實現 PayNotifyInterface 這個接口,並且實現 notifyProcess 這個方法,在這個方法中完成自己的商戶邏輯。然後根據處理結果返回布爾值。

這裏要重點說明的是 TestNotify::notifyProcess(array $data) 這個方法的參數 $data,它是通過sdk內部傳過來的,它返回的信息與配置文件 return_raw的設置有關係。

如果 return_raw = false 返回的是我映射的結果,這裏需要小心,如果你的php報錯級別設置的太高,可能會出現報錯,因爲內部有很多 Undefined index 錯誤,因爲我並未進行檢查,當前可能暫時也不打算修復這個問題。
如果 return_raw = true 則返回的是第三方支付機構的原始數據。

不管是設置成什麼,該參數裏邊都有一個 channel 參數,大家可以根據這個參數區分回調屬於那一個類別。像上面的示例一樣。

PayNotifyInterface 接口

最近有很多人在微信中問我,幹嘛一定要實現這個接口?我這裏舉個例子:
你出去旅行,到了突然發現ios的手機充電線沒帶,怎麼辦?找個便利店買一根好了(因爲附近沒有蘋果店),那麼怎麼買的充電線確保你手機可以用呢?這個很簡單,因爲蘋果把自己充電線的接口標準公佈了,凡事想造蘋果手機充電線的按照這個標準造出來的,你都可以用。

所以接口的作用就是制定一個標準;你們都實現我規定的接口,然後返回布爾值給我,我就可以處理了。至於內部你們想怎麼做,是你們的事情。

通過這個接口完全將簽名與商戶業務邏輯進行了分離,以後你的調整隻圍繞這一個類即可。當然這裏涉及到的思想有 ioc/di ,這又是另外一個話題,空的時候我們聊聊。

聯繫我

我的微信公衆號,歡迎訂閱 icanfo

現在這個公衆號名字不太好,想名字真頭痛。有誰可以給推薦一個?

image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章