銀聯在線支付在2014年重建了一個新的系統(全渠道acp)代替老系統(upop),並2014-2015期間將全部商戶從upop切換到了acp。本文簡要介紹一下銀聯在線支付的兩種主要支付方式:前臺網關支付(用戶的瀏覽器從商戶頁面跳轉到銀聯在線頁面進行支付)和後臺網關支付(用戶在商戶頁面進行支付,商戶後臺系統調用銀聯繫統完成支付)的切換方式。 javascript
此次切換有幾個特色: php
灰度切換。不是全部交易一次性所有切換到acp,而是按照商戶維度分批切換。這就意味着upop和acp兩個系統要同時保持運行。 html
acp的報文格式變了,與upop的報文不兼容,包括請求報文,響應報文,交易成功的異步通知報文,這意味着切換時須要對報文進行轉換。 java
upop保持原url,acp採用新的url。 api
如下是切換過程當中3種類型的商戶的處理方式。 瀏覽器
尚未切換的upop時期入網的老商戶,使用upop url,請求由upop系統處理。 frontend
已經切換的upop時期入網的老商戶,使用upop url,請求由upop作報文轉換後轉發到acp,由acp系統處理。 異步
Acp上線後新入網的商戶,使用acp url,請求由acp系統直接處理。 post
下圖爲前臺網關支付的3種類型商戶的處理流程 網站
這裏咱們主要關注已經切換的upop時期入網的老商戶的處理流程。
以壹基金網站爲例。
首先,用戶來到壹基金的捐款頁面
http://www.onefoundation.cn/index.php?g=home&m=page&a=index&id=73
輸入金額1元,點擊」銀聯在線支付」按鈕這時瀏覽器會訪問http://www.onefoundation.cn/unionPay/action/front.php
壹基金在後臺對」我要捐款1元給壹基金」 生成發送給upop的訂單請求報文,並用商戶私鑰進行簽名, 而後生成包含訂單報文和商戶簽名的自動提交表單,表單的地址爲upop前臺網關地址https://unionpaysecure.com/api/Pay.action ,隨後瀏覽器自動提交表單,訪問upop前臺網關。
<body onload="javascript:document.pay_form.submit();"> <form id="pay_form" name="pay_form" action="https://unionpaysecure.com/api/Pay.action" method="post"> <input type="hidden" name="origQid" id="origQid" value="" /> <input type="hidden" name="acqCode" id="acqCode" value="" /> <input type="hidden" name="merCode" id="merCode" value="" /> <input type="hidden" name="commodityUrl" id="commodityUrl" value="http://dev.one-foundation.com/" /> <input type="hidden" name="commodityName" id="commodityName" value="壹基金愛心捐贈" /> <input type="hidden" name="commodityUnitPrice" id="commodityUnitPrice" value="100" /> <input type="hidden" name="commodityQuantity" id="commodityQuantity" value="1" /> <input type="hidden" name="commodityDiscount" id="commodityDiscount" value="" /> <input type="hidden" name="transferFee" id="transferFee" value="" /> <input type="hidden" name="customerName" id="customerName" value="" /> <input type="hidden" name="defaultPayType" id="defaultPayType" value="" /> <input type="hidden" name="defaultBankNumber" id="defaultBankNumber" value="" /> <input type="hidden" name="transTimeout" id="transTimeout" value="" /> <input type="hidden" name="merReserved" id="merReserved" value="" /> <input type="hidden" name="version" id="version" value="1.0.0" /> <input type="hidden" name="charset" id="charset" value="UTF-8" /> <input type="hidden" name="merId" id="merId" value="210440383989452" /> <input type="hidden" name="merAbbr" id="merAbbr" value="壹基金" /> <input type="hidden" name="transType" id="transType" value="01" /> <input type="hidden" name="orderAmount" id="orderAmount" value="100" /> <input type="hidden" name="orderNumber" id="orderNumber" value="20151015154414354" /> <input type="hidden" name="orderTime" id="orderTime" value="20151015154414" /> <input type="hidden" name="orderCurrency" id="orderCurrency" value="156" /> <input type="hidden" name="customerIp" id="customerIp" value="58.246.226.97" /> <input type="hidden" name="frontEndUrl" id="frontEndUrl" value="http://dev.one-foundation.com/html/cn/beneficence_T_UPay.html" /> <input type="hidden" name="backEndUrl" id="backEndUrl" value="http://dev.one-foundation.com/unionPay/action/back_notify.php" /> <input type="hidden" name="signature" id="signature" value="41f5a7e35baf221c079279bcb5cb7037" /> <input type="hidden" name="signMethod" id="signMethod" value="md5" /> <input type="submit" type="hidden" style="display:none;"> </form>
Upop在收到瀏覽器發來的訂單報文後。先對用商戶公鑰對報文進行驗籤,確保這筆訂單報文確實是由這個商戶發來的,驗籤成功後根據商戶號判斷該商戶是否已經切換到acp,若是商戶還沒切換,則繼續在upop進行後續處理;若是商戶已經切換,則對報文進行轉換,轉換成acp格式的報文,並用銀聯公鑰進行簽名,而後生成包含acp格式報文和銀聯簽名的自動提交表單,表單地址爲acp前臺網關的地址 https://cashier.95516.com/b2c/api/Pay.action,隨後瀏覽器自動提交表單,訪問acp前臺網關。
<form id="defaultForm" action="https://cashier.95516.com/b2c/api/Pay.action" method="post"><input type="hidden" id="accNo" name="accNo" value="" /> <input type="hidden" id="accType" name="accType" value="" /> <input type="hidden" id="accessType" name="accessType" value="0" /> <input type="hidden" id="acqInsCode" name="acqInsCode" value="" /> <input type="hidden" id="backUrl" name="backUrl" value="http://dev.one-foundation.com/unionPay/action/back_notify.php" /> <input type="hidden" id="bindId" name="bindId" value="" /> <input type="hidden" id="bizType" name="bizType" value="000201" /> <input type="hidden" id="cardTransData" name="cardTransData" value="" /> <input type="hidden" id="certId" name="certId" value="0" /> <input type="hidden" id="channelType" name="channelType" value="07" /> <input type="hidden" id="currencyCode" name="currencyCode" value="156" /> <input type="hidden" id="customerInfo" name="customerInfo" value="" /> <input type="hidden" id="customerIp" name="customerIp" value="58.246.226.97" /> <input type="hidden" id="defaultPayType" name="defaultPayType" value="" /> <input type="hidden" id="encoding" name="encoding" value="UTF-8" /> <input type="hidden" id="encryptCertId" name="encryptCertId" value="" /> <input type="hidden" id="frontFailUrl" name="frontFailUrl" value="" /> <input type="hidden" id="frontUrl" name="frontUrl" value="http://dev.one-foundation.com/html/cn/beneficence_T_UPay.html" /> <input type="hidden" id="instalTransInfo" name="instalTransInfo" value="" /> <input type="hidden" id="internal.logId" name="internal.logId" value="1500120122" /> <input type="hidden" id="internal.merReferer" name="internal.merReferer" value="http://www.onefoundation.cn/unionPay/action/front.php" /> <input type="hidden" id="internal.origReqInfo" name="internal.origReqInfo" value="9001|07|0101" /> <input type="hidden" id="issInsCode" name="issInsCode" value="" /> <input type="hidden" id="merAbbr" name="merAbbr" value="壹基金" /> <input type="hidden" id="merCatCode" name="merCatCode" value="" /> <input type="hidden" id="merId" name="merId" value="210440383989452" /> <input type="hidden" id="merName" name="merName" value="壹基金" /> <input type="hidden" id="orderDesc" name="orderDesc" value="" /> <input type="hidden" id="orderId" name="orderId" value="20151015154414354" /> <input type="hidden" id="orderTimeout" name="orderTimeout" value="" /> <input type="hidden" id="payCardType" name="payCardType" value="" /> <input type="hidden" id="payTimeout" name="payTimeout" value="" /> <input type="hidden" id="reqReserved" name="reqReserved" value="" /> <input type="hidden" id="reserved" name="reserved" value="" /> <input type="hidden" id="riskRateInfo" name="riskRateInfo" value="{commodityQty=1&commodityName=壹基金愛心捐贈&commodityUrl=http://dev.one-foundation.com/&commodityUnitPrice=100}" /> <input type="hidden" id="securityType" name="securityType" value="" /> <input type="hidden" id="signMethod" name="signMethod" value="02" /> <input type="hidden" id="signature" name="signature" value="130519e5c6df6053a1410e0e87f099ad" /> <input type="hidden" id="subMerAbbr" name="subMerAbbr" value="" /> <input type="hidden" id="subMerId" name="subMerId" value="" /> <input type="hidden" id="subMerName" name="subMerName" value="" /> <input type="hidden" id="supPayType" name="supPayType" value="" /> <input type="hidden" id="termId" name="termId" value="" /> <input type="hidden" id="tn" name="tn" value="" /> <input type="hidden" id="txnAmt" name="txnAmt" value="100" /> <input type="hidden" id="txnSubType" name="txnSubType" value="01" /> <input type="hidden" id="txnTime" name="txnTime" value="20151015154414" /> <input type="hidden" id="txnType" name="txnType" value="01" /> <input type="hidden" id="userMac" name="userMac" value="" /> <input type="hidden" id="version" name="version" value="1.0.0" /> <input type="hidden" id="vpcTransData" name="vpcTransData" value="" /> </form> <script type="text/javascript"> document.getElementById("defaultForm").submit(); </script>
Acp前臺網關在收到瀏覽器發來的訂單報文後,先用銀聯公鑰對報文進行驗籤,確保這筆訂單報文確實是由銀聯(這裏是upop)生成的。而後對訂單進行驗證,存庫,展現等處理,返回給瀏覽器銀聯在線支付的首頁https://cashier.95516.com/b2c/index.action?transNumber=xxxxxx
<form id="defaultForm" action="https://cashier.95516.com/b2c/index.action?transNumber=201510151544144032128" method="post"> </form> <script type="text/javascript"> document.getElementById("defaultForm").submit(); </script>
用戶在銀聯在線的支付頁面輸入卡號,密碼,短信驗證碼等信息,並點擊支付,瀏覽器便訪問acp前臺網關進行支付。
Acp前臺網關進行一系列支付相關的處理後,成功完成了這筆支付。而後判斷出這筆訂單的商戶是一個」已經切換的upop時期入網的老商戶」,因而生成一個upop格式的後臺通知報文並用銀聯私鑰簽名,而後異步發送給商戶的後臺系統(backendurl),通知商戶這筆交易已經成功完成。同時生成一個upop格式前臺通知報文並用銀聯私鑰簽名,而後把這個前臺通知報文放入支付成功結果頁面的」返回商戶」的按鈕的連接(frontendurl)。商戶在收到前臺通知或者後臺通知報文後,對報文用銀聯公鑰進行驗籤,驗籤成功後則將這筆訂單認定爲成功。
接下來咱們來看後臺網關的交易流程,後臺網關的報文是由商戶系統直接發送給銀聯繫統的下圖爲後臺網關支付的3種類型商戶的處理流程
和前臺網關支付相同,這裏咱們主要關注已經切換的upop時期入網的老商戶的處理流程。