開題
現(xiàn)在網(wǎng)絡(luò)支付方式越來越發(fā)達(dá)而昨,已經(jīng)不可避免地開始與各類 IT 系統(tǒng)集成们何。在財務(wù)制度比較規(guī)范的地方态蒂,這類入賬自然需要統(tǒng)一管理,資金不能隨意流動辽社。如果由各個業(yè)務(wù)系統(tǒng)自己去申請對接網(wǎng)絡(luò)支付接口伟墙,自然是很難實現(xiàn)統(tǒng)一管理的,而且也麻煩滴铅。
因此戳葵,就需要一個統(tǒng)一的企業(yè)級支付平臺作為中間層,來負(fù)責(zé)各業(yè)務(wù)系統(tǒng)與網(wǎng)絡(luò)支付的對接汉匙。這樣拱烁,不僅方便了財務(wù)數(shù)據(jù)的統(tǒng)一提取、賬戶對賬噩翠,也使企業(yè)支付平臺可以代表所有的業(yè)務(wù)系統(tǒng)與網(wǎng)絡(luò)支付接口進(jìn)行交互戏自,業(yè)務(wù)系統(tǒng)不會接觸到企業(yè)的網(wǎng)絡(luò)支付總密鑰,較為安全可控伤锚。
這樣的例子其實我們天天見擅笔。例如 12306 的車票支付、教育部考試中心的考試費支付屯援,都采用了中間層猛们,來接入多個網(wǎng)絡(luò)支付平臺。
此時狞洋,企業(yè)級支付平臺的角色可以認(rèn)為是一個代理弯淘,協(xié)助業(yè)務(wù)系統(tǒng)完成支付流,并保存相關(guān)數(shù)據(jù)吉懊。目前這類“代理”的架構(gòu)并沒有標(biāo)準(zhǔn)庐橙,所以實現(xiàn)起來會各有小差別假勿。如何去定義企業(yè)級支付平臺(下稱企業(yè)層)和業(yè)務(wù)系統(tǒng)各自的角色,就會決定架構(gòu)的實現(xiàn)方式态鳖,相應(yīng)就會影響到支付業(yè)務(wù)的實現(xiàn)情況转培。
WePay 的實現(xiàn)思路
下面介紹一款已經(jīng)在運行中的企業(yè)支付平臺 WePay,其目前向上對接了微信企業(yè)號的微信支付接口郁惜,遠(yuǎn)期規(guī)劃可加入其他網(wǎng)絡(luò)支付的支持堡距。
WePay 會給每個業(yè)務(wù)系統(tǒng)分配一個“子商戶”,對應(yīng)會有 ID 和密鑰兆蕉,也就意味著業(yè)務(wù)系統(tǒng)通過 WePay 實現(xiàn)的子商戶進(jìn)行支付請求羽戒,WePay 自己處理網(wǎng)絡(luò)支付接口的密鑰,應(yīng)用系統(tǒng)只能借助 WePay 獲取網(wǎng)絡(luò)支付的結(jié)果信息虎韵。
上圖的流程目前其實工作得非常好易稠。應(yīng)用系統(tǒng)需要完成的工作很簡單,生成應(yīng)用端的訂單信息并保存訂單號包蓝,然后把訂單信息一股腦前臺 POST 給 WePay驶社,WePay 的網(wǎng)頁會幫應(yīng)用系統(tǒng)實現(xiàn)支付過程,應(yīng)用系統(tǒng)只管收支付結(jié)果就可以了测萎。
在這里亡电,WePay 的角色并不只是“代理”那么簡單了,因為要幫應(yīng)用系統(tǒng)實現(xiàn)支付流程硅瞧,所以中間還得控制支付過程份乒。我就暫且叫它做“富代理”吧。
為了更好地說明純粹的“代理”是個什么情況腕唧,我假設(shè)了新的流程或辖。這里業(yè)務(wù)系統(tǒng)會把 WePay 當(dāng)作是網(wǎng)絡(luò)支付的服務(wù)器,所以業(yè)務(wù)系統(tǒng)傳給 WePay 的 ID 可以是自編號的子商戶枣接,WePay 把請求遞交給網(wǎng)絡(luò)支付的時候再用上網(wǎng)絡(luò)支付統(tǒng)一的密鑰颂暇。
代理與否但惶,利弊明顯耳鸯。實際上現(xiàn)在基本上都是“富代理”的解決方案。
- 純代理
- 業(yè)務(wù)系統(tǒng)需要自己處理支付過程(圖中榆骚,瀏覽器端中間的藍(lán)棧頁面均由應(yīng)用服務(wù)器實現(xiàn))片拍;
- 不同系統(tǒng)的技術(shù)良莠不齊,支付過程的體驗和安全性會有差別妓肢,不利于企業(yè)對支付過程進(jìn)行標(biāo)準(zhǔn)化;
- 但如果業(yè)務(wù)系統(tǒng)已經(jīng)做了現(xiàn)有的網(wǎng)絡(luò)支付對接(目前網(wǎng)絡(luò)支付有大量的 SDK)苫纤,技術(shù)上碉钠,純代理模式下業(yè)務(wù)系統(tǒng)會更容易接入企業(yè)層系統(tǒng)纲缓。
- 富代理
- 支付過程由 WePay 實現(xiàn)(圖中,瀏覽器端中間的藍(lán)棧頁面均由 WePay 實現(xiàn))喊废;
- 如果應(yīng)用是從頭開發(fā)的祝高,接入的工作量就會比直接接入網(wǎng)絡(luò)支付少(即便人家有 SDK 了還得自己實現(xiàn)前端呢);
- 支付過程均由企業(yè)層實現(xiàn)污筷,用戶體驗和安全性可以由企業(yè)層的統(tǒng)一實現(xiàn)來保證工闺。
“富代理”角色可以多做這點判斷
企業(yè)層需要做的事情多了,這樣的角色定位下瓣蛀,每單支付業(yè)務(wù)系統(tǒng)該給企業(yè)層傳多少參數(shù)呢陆蟆?
根據(jù)內(nèi)部公開資料得知,目前業(yè)務(wù)系統(tǒng)在創(chuàng)建支付訂單時惋增,需要傳以下這些參數(shù)給這款 WePay 系統(tǒng)叠殷。我做了下分類:
-
請求身份和請求校驗
-
spbillCreateIp
發(fā)起訂單的 IP -
tenant
租戶代碼(由 WePay 分配) -
timestamp
訂單生成的時間戳 -
sign
所有參數(shù)加上密鑰后的簽名值
-
-
訂單內(nèi)容(必須)
tradeType
交易類型-
totalFee
支付金額(單位為分) -
tenantTradeNumber
租戶訂單號(業(yè)務(wù)系統(tǒng)內(nèi)部唯一) -
redirectUrl
前端跳轉(zhuǎn)確認(rèn)地址
-
訂單內(nèi)容(增強)
-
productBody
,productDetail
交易內(nèi)容和詳情 -
tenantUserCode
,tenantUserName
企業(yè)應(yīng)用中用戶的用戶名、姓名
-
實際上這一整套接口的參數(shù)內(nèi)容诈皿,多是直接借鑒微信支付的參數(shù)來著的林束,反正就是轉(zhuǎn)發(fā)參數(shù),用現(xiàn)成的參數(shù)名也沒啥問題稽亏。
但注意到 tradeType
這個參數(shù)了嗎壶冒?實際上這個參數(shù)是微信支付用的。微信那邊目前支持的值有 JSAPI
(微信內(nèi)瀏覽器)截歉、NATIVE
(用戶掃碼付款)胖腾、APP
(手機應(yīng)用)、MWEB
(微信外手機瀏覽器)怎披、MICROPAY
*(商戶條碼付款)胸嘁,而 WePay 實現(xiàn)了 JSAPI
和 NATIVE
,根據(jù)業(yè)務(wù)系統(tǒng)發(fā)的參數(shù)來返回給瀏覽器不同的界面凉逛。
那么性宏,這個參數(shù)真的要靠業(yè)務(wù)系統(tǒng)來給定嗎?
- 大多數(shù)情況下状飞,業(yè)務(wù)系統(tǒng)需要根據(jù)客戶端來提供不同的界面來適配毫胜,比如根據(jù) UA 有沒有 micromessenger,判斷提供 PC 版還是微信版诬辈。業(yè)務(wù)系統(tǒng)很多時候似乎知道客戶端屬性了酵使,讓業(yè)務(wù)系統(tǒng)來指定這個類型,下不同的單焙糟,似乎順理成章口渔。
- 然而,當(dāng)今的網(wǎng)頁技術(shù)早已可以實現(xiàn)一套前端模板穿撮,通吃 PC 移動(Bootstrap 框架 推了很多不會寫響應(yīng)式設(shè)計的人一把)缺脉。因此痪欲,有的業(yè)務(wù)系統(tǒng)根本沒必要去判斷客戶端是不是微信(而提供不同的界面)。這時候讓業(yè)務(wù)系統(tǒng)來下單攻礼,業(yè)務(wù)系統(tǒng)肯定下一個 PC 版的單了业踢,除非非常考究礁扮,才會特意適配一下微信知举。
- 此外前文提到,企業(yè)層在支付流程中太伊,會協(xié)助應(yīng)用系統(tǒng)實現(xiàn)面向用戶的支付交互流程(前端)雇锡。而顯然,
JSAPI
倦畅、NATIVE
遮糖、MWEB
這三種模式,只是觸發(fā)支付的方式不同叠赐,并不會影響到支付業(yè)務(wù)的核心內(nèi)容和最終結(jié)果欲账。這種情況下,顯然沒有必要讓應(yīng)用去選擇下單模式芭概,而應(yīng)該讓企業(yè)層來統(tǒng)一判斷赛不,從而繼續(xù)降低業(yè)務(wù)系統(tǒng)的集成難度。JSAPI
創(chuàng)建訂單的時候需要OPENID
罢洲,可能有的業(yè)務(wù)會靠這個參數(shù)來限制只能某人支付這一訂單踢故。實際上這個需求并非必要,很多時候反而會造成業(yè)務(wù)規(guī)則不統(tǒng)一(支付頁面如果可以分享惹苗,會導(dǎo)致OPENID
不同而支付失數罱稀;不限制的話桩蓉,雖然可能會有退款退不到賬戶本人的問題淋纲,但很多業(yè)務(wù)直接上NATIVE
模式,誰掃碼都行院究,完全沒考慮這一點)洽瞬,確實有業(yè)務(wù)需要的話也可以保留,就是 WePay 多判斷一下而已业汰。
- 更重要的是伙窃,這三種模式是高度與特定的網(wǎng)絡(luò)支付端口耦合的。如果日后需要接入其它的網(wǎng)絡(luò)支付样漆,較好的辦法是業(yè)務(wù)系統(tǒng)不用管網(wǎng)絡(luò)支付端口的具體的支付模式參數(shù)为障,而靠 WePay 去給用戶選擇,否則業(yè)務(wù)系統(tǒng)全得再改一遍,多沒意思产场。
結(jié)論就是鹅髓,這個 tradeType
應(yīng)當(dāng)做一下整合舞竿。鑒于JSAPI
京景、NATIVE
、MWEB
這三種模式本質(zhì)上都是網(wǎng)頁支付骗奖,可以在 WePay 端整合為一個名字(如 HTML
)确徙,再由 WePay 進(jìn)行選擇,而不應(yīng)該讓業(yè)務(wù)系統(tǒng)來選执桌。如果業(yè)務(wù)系統(tǒng)還發(fā)了這三個串進(jìn)來鄙皇,就統(tǒng)一定向到新的 HTML
模式就好。至于 APP
和 MICROPAY
仰挣,現(xiàn)在這個系統(tǒng)似乎沒有用到伴逸,這些方式就預(yù)留著空位就好。
支付中間層如何判斷支付模式膘壶?
既然提出了這個解決方案错蝴,自然也得考慮,沒有業(yè)務(wù)系統(tǒng)的任何數(shù)據(jù)颓芭,支付層能不能高效率地自行判斷支付模式呢顷锰?當(dāng)然是可以的。
支付中間層最麻煩的事情亡问,莫過于在開始讓用戶支付前官紫,就得先跟網(wǎng)絡(luò)支付開好訂單。而開訂單的時候州藕,就必須決定具體的支付模式束世。
有種穩(wěn)妥的方法,就是通過前端來檢查微信的 JSAPI 能不能用床玻、有沒有手機(微信)毁涉,再來按需異步開訂單。不過這樣當(dāng)然太麻煩了笨枯,所以靠粗暴的后端 User Agent 檢查薪丁,就可以實現(xiàn)絕大多數(shù)情況下的正確及時判斷了。
所以是:
- UA 判斷是否包含了
micromessenger
馅精,是的話严嗜,默認(rèn)在微信環(huán)境下,開 JSAPI 訂單- 調(diào) JSAPI 需要獲取
OPENID
洲敢,企業(yè)號的接口無論微信用戶是否有關(guān)注企業(yè)號漫玄,都會返回一個OPENID
,而且鑒于支付是低頻操作,這個時候讓
WePay 跳一次 OAuth 其實也并不太影響響應(yīng)時間(OAuth 有兩種方案睦优,一種是 WePay 自己跟微信拿數(shù)據(jù)然后 Cookie 緩存渗常,另一種是跟企業(yè)號應(yīng)用主域名拿數(shù)據(jù),由于企業(yè)號域名通常用戶都有登陸汗盘,都帶 Cookie皱碘,可能可以節(jié)省 OAuth 的開銷)
- 調(diào) JSAPI 需要獲取
- 其他情況全部走 NATIVE 訂單;或者隐孽,如果有閑心兼容下 MWEB(手機瀏覽器在這個模式下可以直接拉起微信癌椿,體驗會更好),就再 UA 判斷是否包含 Android 或 iPhone / iPad 串菱阵,有的話就進(jìn) MWEB踢俄,沒有就進(jìn) NATIVE 掃碼去
- 要做到 100% 靠譜,就得考慮在 WePay 端提供切換模式的功能了晴及,不過一切換模式都办,就得關(guān)閉訂單,還得重新生成訂單號給網(wǎng)絡(luò)支付用虑稼,是挺煩的琳钉,所以沒必要做
EOF
說明:本文資料均來自公網(wǎng)公開資料,圖是自己用這個畫的动雹,并沒有透露什么機密槽卫。終于可以安心學(xué)習(xí)了 = =
本文采用知識共享“署名-非商業(yè)性使用 4.0”許可協(xié)議授權(quán),如需額外授權(quán)請與本人聯(lián)系胰蝠。