如題今天要描述一個問題是:程序在確認訂單時拉起第三方支付,支付失敗了,引發的問題。程序員
爲了能清楚的描述問題,我把場景復現一下,你們確定都有過APP購物的體會,你們必定知道有一個按鈕叫「確認」或者「結算」之類的功能按鈕,
點擊一下彈出一個框讓進行微信支付或支付寶支付或銀聯支付或其餘什麼支付的。
那麼這個「確認」或者「結算」功能按鈕在背後到底作了哪些事情,成功或失敗是怎麼處理的,須要怎麼處理,這些都是值得討論的問題。
咱們在作商城時就遇到了這樣的問題,咱們的問題是咱們第一次點擊「確認」按鈕時程序報錯說支付失敗了,第一次失敗沒問題呀,可能就是支付有問題吧,
那麼咱們再次支付唄,OK,那咱們再點,這個時候又報錯了,說購物車爲空,咱們測試的妹妹就暈了。
明明頁面上購物車裏有商品啊,誰說的爲空,你本身看嘛,你本身看嘛,誰說的爲空。數據庫
這就是咱們的問題。服務器
那麼遇到這樣問題怎麼辦,咱們把問題細化,細化,在細化,咱們一步一步看每個步驟。
而後咱們會看到在訂單提交,支付付款時,這裏邊的過程須要細化的地方就是,
先要建立訂單把用戶購物車裏全部的商品、優惠券、積分等全部東西計算好以後把的結果落庫,把購物車清空。而後在向微信、支付寶等發起支付。微信
這裏細化出來了兩步:測試
一、建立訂單,清空購物車
二、向第三方支付平臺支付。微信支付
既然分出來了兩步那麼每一步就都會有出錯的可能,每一步均可能出錯。出錯並不可怕,可怕的是出錯不認,知錯不改,明知故犯。
上邊的兩步必須是順序的執行,也就是說若是第一步出錯,那麼第二部不用執行了,而若是第一隻執行成功,第二步失敗,這個問題就比較麻煩。
這就是咱們的測試妹妹看到的問題,
第一次是真的支付失敗了,可是建立訂單成功了,因此購物車在後臺數據庫清空了,而頁面沒有刷新,第二次呢購物車真的是清空了,在也沒法支付了,由於後臺會從新檢測購物車。spa
咱們先來這樣討論問題事務
首先咱們已經把上邊說步驟分紅了兩步,那麼咱們就按照兩步的方式來思考問題,
每一步在一個單獨的事務裏。爲何要這麼看,好像APP的開發人員說支付這一步驟是APP直接調用微信或支付寶不通知服務器端的。
那麼只有第一步是服務器徹底能夠控制而且在本身的一個事務裏,那麼能夠給APP一個約定,成功怎麼處理,失敗怎麼處理。
若是失敗還好,直接說你不用走第二步,固然失敗不是咱們指望的,咱們也不但願失敗,因此第一步成功了。
那麼到第二步怎麼辦呢,這裏按以前所說的這一步是APP直接拉起微信或支付寶的,服務器端根本不知道,
那麼這裏的問題就來了,若是支付成功,固然是咱們指望的一個結果,直接寫會數據庫,支付成功回寫,這沒有問題,是咱們指望的結果。支付寶
(這裏沒有討論,在支付成功後回寫失敗怎麼辦,這也是一個大坑,雖然機率不大,可是不能假設,特別是量大的時候,一旦出了問題,用戶但是真的付錢了,很是特別的麻煩。你拿用戶錢,告訴用戶沒有支付,不給用戶東西,你搶錢嘛)開發
那麼支付失敗怎麼辦,咱們的焦點問題就是若是支付失敗了,APP又不刷新,仍然可以看到購物車裏有商品,
而實際上由於第一步的調用成功,購物車已經被清空,購物車裏的商品已經落庫成爲了訂單。
這時不能在對購物車進行支付,而其實是訂單。訂單的狀態是未支付或者支付未成功。
討論到這裏,咱們已經很是明確的看到如下內容,首先在顯示上混淆了支付的是訂單仍是購物車,
由於在APP上顯示的是操做一次,按了一個按鈕發起兩個調用,讓用戶感受到或者給你迷惑的感受的是我此次是對購物車進行的支付,
買的是購物車裏的商品嘛,但其實是因爲APP在進行了第一次建立訂單調用後,緊接着直接拉起支付,沒有通知服務器。
這是兩個步驟在一塊兒有沒有很好的異常處理或回滾機制,看似友好減小用戶操做的行爲倒是給用戶形成了極大的麻煩。
首先這裏必定要明確的是支付的必定是訂單,不是購物車。
固然用戶是能夠不用感知到支付的是購物車或者是訂單的,也能夠不用感覺到有任何變化的,這個時候若是兩次調用所有成功或一塊兒失敗,都是沒有問題的,
但咱們的問題就是用戶沒有任何感知的狀況下,第一個調用成功了,第二個失敗了,APP尚未任何變化,或者沒有刷新的意願,
那麼第一個數據想回滾,或者有回滾的意願,或者想有其餘的處理,問題就來了。
對於這樣的一個分析,上邊解決問題是思路相對也比較明確,
第一種,那就分紅兩步,每一步單獨處理,從業務流程上給出一個解決方案,
就是能夠一塊兒提交,可是若是是第一步成功,第二步失敗了,那麼在這個時候,APP上能夠給給提示,好比說:你的訂單已經提交可是支付失敗請儘快完成支付,等。
或者乾脆就是直接分紅兩步,第一步訂單提交,並給出提示。第二,訂單支付並給出提示。
第二種,咱們假設這個支付能夠有服務器端發起,把建立訂單落庫和支付的業務放進一個事務裏,一樣是一次調用,那麼因爲事物的支持,能夠一塊兒失敗,一塊兒成功,這想來是比較棒的解決方案。
第三種可能,是否是能夠有APP來發起事務,而後第二調用失敗了,讓第一次操做取消,那這裏就涉及到兩種方案,
第一種,使用事務,讓第一次的提交在第二支付成功時,才真正落庫。
第二種,能夠把第一次是數據庫狀態變成提交前的狀態,至關於回滾,但實際上更加相似又從新了一份數據,或者更改原來的爲落庫前的狀態。
或者第三種,讓用戶先支付成功,而後在寫訂單,(這種感受是騷主意吧,還涉及到庫存,那一超賣,在那個點上賣完了怎麼辦)
第四種可能,APP同時把本身拉起支付調用的支付結果在告訴服務器,讓服務器來返回APP的這一次行爲是最終該怎麼辦。
其餘解決方案,歡迎你們一塊兒吐槽,討論~
回來散步時又想到一種辦法,
第五種辦法,在用戶點「確認」或「結算」按鈕時,在服務器端校驗除了校驗購物車是否是爲空的話,
再校驗最近的沒有支付或者支付失敗的訂單的,對比一下點擊按鈕的時間和訂單的時間,在某個可容許的範圍內,能夠假設就是支付的這個訂單。
(想來這個也是一種不算好的辦法,但理論上也能夠解決這樣狀況的大部分問題)
原本我想是很是簡單的問題,除了第三種然APP來作事務相對困難,其餘的都是業務流程稍微變化一下就能很好的解決問題,
可是我反應了幾回這樣的問題,也是沒人理我,感受世界好悲哀。
有人認定了建立訂單有問題,有人說支付有問題,支付不成功嘛,我給人解釋,可是感受...就是那種感受「他人笑我太瘋癲,我笑他人看不穿」。
可是就像我上邊說的出錯不認,知錯不改,產品不改進,用戶體驗差,拼命的讓程序員改一些明明流程問題引發的看似是BUG的問題,可憐那些悲催的程序員吧。