掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
今天得到一個(gè)項(xiàng)目的反饋:你們新增加的支付方式支付正常,但原來支付的流程總是付了錢卻沒反應(yīng)。這消息本身是很常見的支付回調(diào)異常。而這個(gè)項(xiàng)目比較特殊,原來開發(fā)并不是我們,很多比較流程都是原來就有的,支付流程的業(yè)務(wù)邏輯也是比較復(fù)雜的,因此在新增加的流程中支付也調(diào)用原來的就已經(jīng)存在支付業(yè)務(wù)邏輯的(主要是不想動(dòng)原來的核心流程,陳年老項(xiàng)目可不敢輕易動(dòng),哈哈);而且原來的支付流程一直都是通暢的,包括接入到原來支付模塊的新增流程也是正常的,說明已經(jīng)存在的支付業(yè)務(wù)邏輯是可用的。
其實(shí)支付回調(diào)異常是很常規(guī)的問題,一般來說是可以非??焖俣ㄎ坏模畹湫偷膬蓚€(gè)問題就是:1、支付商戶號(hào)異常更新導(dǎo)致異常;2、支付回調(diào)業(yè)務(wù)代碼執(zhí)行錯(cuò)誤或邏輯錯(cuò)誤。
首先,筆者注意到的是數(shù)據(jù)庫(kù)的支付訂單id號(hào)是間斷的,而id號(hào)本來是原來開發(fā)設(shè)置為自動(dòng)自增的,理論上是連續(xù)的。說明在此過程中,有訂單會(huì)被刪除的過程。后面發(fā)現(xiàn)原來的支付業(yè)務(wù)邏輯確實(shí)會(huì)不停刪除支付訂單,基本邏輯就是二次發(fā)起支付會(huì)先刪除原來已經(jīng)存在但沒支付完成的訂單,然后生成新的支付訂單。本質(zhì)的目的就是為了刷新支付訂單號(hào)(可能原來的開發(fā)者是為了避免支付訂單超時(shí)等問題吧)。
但上述設(shè)計(jì)本身也是不夠優(yōu)雅的,比如刪除、新增數(shù)據(jù)的開銷比更新數(shù)據(jù)要大很多,同時(shí)不做任何判斷就直接刷新訂單號(hào)也不是優(yōu)雅的做法。
結(jié)合此前支付流程都是沒問題的,首先我們懷疑的是不是某個(gè)bug引起原來支付流程中刪除訂單+創(chuàng)建新訂單的(也就是刷新訂單號(hào))問題,導(dǎo)致a訂單在用戶支付到銀聯(lián)商務(wù)這個(gè)支付平臺(tái)發(fā)送回調(diào)這個(gè)時(shí)間差內(nèi),系統(tǒng)錯(cuò)誤的刪除了a訂單,而創(chuàng)建了新的b訂單,這樣回調(diào)的信息是a訂單,自然不能正常完成回調(diào)邏輯。
然而實(shí)際上通過程序debug模式的日志發(fā)現(xiàn),壓根就沒有查看到支付回調(diào)相關(guān)的日志,而其它所有操作流程的日志都是準(zhǔn)確無誤的。
這個(gè)時(shí)候聯(lián)想到銀聯(lián)商務(wù)平臺(tái)后臺(tái)操作體驗(yàn)與支付寶微信的差距很大,筆者甚至懷疑其銀聯(lián)商務(wù)這個(gè)支付平臺(tái)起來,懷疑是不是平臺(tái)的bug導(dǎo)致部分訂單回調(diào)消息沒有及時(shí)發(fā)送(差點(diǎn)就誤會(huì)了,哈哈)。但細(xì)想起來,人家那么大的平臺(tái)而且跟錢有關(guān)的東西不可能犯這么低級(jí)的錯(cuò)誤。
所以再次查看了服務(wù)器nginx的日志,發(fā)現(xiàn)在nginx日志里面出現(xiàn)了支付回調(diào)的痕跡。而且發(fā)現(xiàn)返回的狀態(tài)碼是非常少見的499狀態(tài)碼。
大家一般常見的http狀態(tài)碼有2xx有200,3xx有301、302,4xx有401、404、403、405,5xx有500、502等等,但499狀態(tài)碼很少見。
大家都知道4xx狀態(tài)碼意味著客戶端的錯(cuò)誤,比如401意味著用戶身份認(rèn)證不通過,404意味著查找的資源不存在(非常常見的錯(cuò)誤碼),403禁止訪問,405請(qǐng)求的方法被禁止。當(dāng)然雖然說4xx狀態(tài)碼都說客戶端的錯(cuò)誤,但實(shí)際上還是服務(wù)端沒有相關(guān)的資源或者客戶端的請(qǐng)求不符合服務(wù)端的要求。
通過查詢相關(guān)的資料得知:
499錯(cuò)誤碼是由于客戶端發(fā)起請(qǐng)求后,一段時(shí)間內(nèi)沒有收到代理服務(wù)器的應(yīng)答,導(dǎo)致連接失敗??赡茉虬ǎ?. 代理服務(wù)器認(rèn)為客戶端發(fā)起的請(qǐng)求過于危險(xiǎn),所以主動(dòng)給斷了; 2. 代理服務(wù)器實(shí)在么得辦法連接到其他服務(wù),導(dǎo)致超時(shí)。
1、排除是由于銀聯(lián)商務(wù)平臺(tái)穩(wěn)定性問題。
不更改支付流程的任何邏輯,只是把回調(diào)通知地址改成其它服務(wù)器的某個(gè)回調(diào)接口地址。結(jié)果發(fā)現(xiàn)在新的回調(diào)地址都能返回200正常的狀態(tài)碼。所以可用排除時(shí)銀聯(lián)商務(wù)平臺(tái)發(fā)送的回調(diào)數(shù)據(jù)有啥問題的可能。
2、排除是由于回調(diào)信息被服務(wù)器拒絕。
因?yàn)橹笆且恢北换卣{(diào)信息請(qǐng)求到并完成整個(gè)業(yè)務(wù)流程的,而且這種正規(guī)的支付平臺(tái)原來開發(fā)者也沒必要做特別的限制。而且上面通知到其它接口也是正常的狀態(tài)碼,因此這個(gè)可能也可用排除。
3、排除是由于項(xiàng)目所在服務(wù)器配置的問題。
在當(dāng)前服務(wù)器創(chuàng)建一個(gè)全新的空白項(xiàng)目,新項(xiàng)目就是提供一個(gè)回調(diào)接口,測(cè)試發(fā)現(xiàn)該新項(xiàng)目測(cè)試接口得到的結(jié)果是跟上面測(cè)試一樣正常的,因此也可用排除。
4、排除是由于整個(gè)項(xiàng)目底層框架對(duì)回調(diào)信息的錯(cuò)誤處理。
在當(dāng)前項(xiàng)目,新建一個(gè)空白控制器,提供一個(gè)空白的訪問接口。經(jīng)過回調(diào)測(cè)試發(fā)現(xiàn)跟上面的結(jié)果還是一樣,還是返回預(yù)期內(nèi)的結(jié)果。
排除了這么多,說明問題的根源還是在于原來開發(fā)者開發(fā)的這個(gè)支付回調(diào)邏輯中除了問題,很可能就是因?yàn)槟撤N故障造成的請(qǐng)求超時(shí)。結(jié)果筆者發(fā)現(xiàn)原來開發(fā)者在處理回調(diào)信息的時(shí)候,非常復(fù)雜,走了很多完全跟項(xiàng)目業(yè)務(wù)邏輯關(guān)系不大的流程,而且拐彎抹角(我甚至懷疑這些代碼是不是東拼西湊來的)。結(jié)果通過不停斷點(diǎn)測(cè)試,外加溯源n層方法調(diào)用,發(fā)現(xiàn)了這么一段。
通過這么一段的邏輯我們可用判斷原開發(fā)者的邏輯:1、信息推送測(cè)試,但是在上線前竟然沒撤掉,也沒做任何處理;2、是不是信息非法提交的后門邏輯,畢竟這些信息都是姓名、身份證號(hào)碼、身份證照片等敏感信息。
?最終的問題所在也是出在這個(gè)地方,由于這里請(qǐng)求的外部接口之前是正常訪問的,而限制接口已經(jīng)失效了,再加上沒有做任何處理。而去剛好原來已經(jīng)有的支付流程的傳入?yún)?shù)在某些情況下剛好符合這段代碼的執(zhí)行條件,于是就執(zhí)行了這些業(yè)務(wù)邏輯。之前外部接口是正常的自然回調(diào)也是正常的,現(xiàn)在外部接口失效了,于是回調(diào)請(qǐng)求就一直卡著不動(dòng),銀聯(lián)商戶那邊作為客戶端也不會(huì)太傻,可能直接斷開服務(wù)鏈接,于是就造成了499返回碼。
看了這個(gè)案例你還敢隨隨便便使用某些來歷不明的源代碼么,即便你敢用,你還會(huì)覺得用這些不明來源的源代碼會(huì)幫你省錢嗎?即便有人愿意修改,這修改維護(hù)的代價(jià)可能比新開發(fā)還要大,因?yàn)榻邮值钠渌魏伍_發(fā)者可能排查各種坑所花的時(shí)間比自己新開發(fā)還要多。
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流