1. 程式人生 > 其它 >asp.net core 3.1開發交通銀行支付介面筆記一底層程式碼

asp.net core 3.1開發交通銀行支付介面筆記一底層程式碼

技術標籤:asp.net core

asp.net core 3.1開發交通銀行支付介面筆記二支付

asp.net core 3.1開發交通銀行支付介面筆記三退款、查詢和收尾

例行吐槽

這個介面上一年很早時候客戶就和銀行對接了。知道元旦後才給的介面。這效率。。。沒誰了。所以,我回老家過完元旦趕緊火急火燎的趕回來寫碼。按照經驗,這
個介面只要寫得好沒歧義、完整難度不大。如果有原始碼介面DEMO提供,速度可以控制在半天內。可是呢提供過來有助於開發的只有2個

1:交通銀行“慧智付”報文交換規範(商戶正式版)文件(只有介面說明連流程都沒有)

2:簽名驗籤方法程式碼(java版一份,socket版其它語言一份)

當時沒說明這個socket是幹嘛的,java的還是看使用配置說明看出是java版。socket我看了是java的包,頓時懵逼結果一頓很久的溝通操作後回覆說其它語言用socket,我去,在說明包裡面加個說明文件就那麼難?好了,接下來開始

開始開發前的選擇

因為我這個專案要求手機公眾號支付,當時因為不懂交行支付是啥流程,文件也沒寫流程。

於是自己按照經驗設計是跳轉交行他們的H5頁面輸入卡號資訊支付完成後再跳轉回來

文件沒有寫流程只好看文字盲猜選定跳轉支付扣款,不過後來又折騰了一頓客戶和交行開發人員一起建了個群,通過諮詢得知,這個這個跳轉支付是在本地網頁點選支付>跳轉交行伺服器>輸入微信密碼>完成支付。唉在文件加個流程就這麼難?

配置:原來SOCKET啟動後傳送加簽資訊返回00000000聯絡了交行技術人員,然後提供了2個商戶號。一個加簽用一個交易用。。。。這操作。。。

按照說明書放置電子證書。寫配置商戶號和密碼。日誌路徑即可。文件這個倒是寫的明白。

開始開發

第一步:寫底層程式碼。這裡程式碼比較多。就放入有代表性的一些意思意思即可

第一點:先是生成xml資訊的

其它的生成只要按照這個生成即可

        /// <summary>
        /// 生成支付報文
        /// </summary>
        /// <param name="orderNo">訂單號</param>
        /// <param name="pay">支付金額</param>
        /// <param name="tranContent">客戶看的內容</param>
        /// <param name="remark">後臺看的備註</param>
        /// <returns></returns>
        public static string CreatePayMessage(string orderNo, decimal pay, string tranContent, string remark)
        {
            XmlDocument xmldoc = new XmlDocument();
            //加入XML的宣告段落:<?xmlversion="1.0" encoding="utf-8"?>
            XmlDeclaration xmldecl = xmldoc.CreateXmlDeclaration("1.0", "utf-8", null);
            xmldoc.AppendChild(xmldecl);
            //root節點
            XmlElement rootNode = xmldoc.CreateElement("Document");
            rootNode.AppendChild(createHeadXML(xmldoc, "介面標識號"));
            rootNode.AppendChild(createPayBodyXML(xmldoc, orderNo, pay, tranContent, remark));
            xmldoc.AppendChild(rootNode);
            return signMessage(xmldoc);
        }
        /// <summary>
        /// 生成支付內容XML
        /// </summary>
        /// <param name="xmldoc">主XML</param>
        /// <param name="orderNo">訂單號</param>
        /// <param name="pay">支付金額</param>
        /// <param name="tranContentStr">客戶看的內容</param>
        /// <param name="remark">後臺看的備註</param>
        /// <returns></returns>
        private static XmlElement createPayBodyXML(XmlDocument xmldoc, string orderNo, decimal pay, string tranContentStr, string remark)
        {
            XmlElement bodyNode = xmldoc.CreateElement("Body");
            //商戶交易編號
            XmlElement payMerTranNo = xmldoc.CreateElement("PayMerTranNo");
            payMerTranNo.InnerText = orderNo;
            bodyNode.AppendChild(payMerTranNo);
            //線上或線下
            XmlElement location = xmldoc.CreateElement("Location");
            location.InnerText = "ONLINE";
            bodyNode.AppendChild(location);
            //交易場景
            XmlElement tranScene = xmldoc.CreateElement("TranScene");
            tranScene.InnerText = "B2C-JSAPI-WECHAT";
            bodyNode.AppendChild(tranScene);
            //金額
            XmlElement amount = xmldoc.CreateElement("Amount");
            amount.InnerText = pay.ToString("0.00");
            bodyNode.AppendChild(amount);
            //幣種
            XmlElement currency = xmldoc.CreateElement("Currency");
            currency.InnerText = "CNY";
            bodyNode.AppendChild(currency);
            //交易內容
            XmlElement tranContent = xmldoc.CreateElement("TranContent");
            tranContent.InnerText = tranContentStr;
            bodyNode.AppendChild(tranContent);
            //商戶內部備註
            XmlElement merMemo = xmldoc.CreateElement("MerMemo");
            merMemo.InnerText = remark;
            bodyNode.AppendChild(merMemo);
            //交易選項(暫時不用。留著)
            //交易失效時間
            XmlElement validPeriod = xmldoc.CreateElement("ValidPeriod");
            validPeriod.InnerText = DateTime.Now.AddMinutes(30).ToString("yyyyMMddHHmmss");
            bodyNode.AppendChild(validPeriod);
            //後臺通知地址
            XmlElement notifyURL = xmldoc.CreateElement("NotifyURL");
            notifyURL.InnerText = GlobalData.TranInfo["notifyurl"];
            bodyNode.AppendChild(notifyURL);
            //前臺通知地址(暫時不用微信公眾號無法通知,員工後臺讓操作員自己重新整理頁面即可)
            //需要通知中返回的欄位(暫時不用)
            return bodyNode;
        }

第二點:加簽解籤。

要吐槽一下。文件給的這段極為有歧義,這個AttachedSign和AttachedVerify沒說明是啥。就寫這個英文單詞在這裡,因為看了java程式碼,當時我理解成是加簽後的字串,或者呼叫java裡面的一個加簽方法。,然後可想而知,一頓操作猛如虎,返回加簽0000000,問了技術人員才知道正確意思。又浪費N多時間

加簽,這裡注意。是要AttachedSign開始到末尾的位元組長度。不是字元長度。這裡文件沒仔細看。。。。可是呢?如果長度<文件位元組長度才出現問題,當然。。這個長度是從單詞AttachedSign或AttachedVerify開始算起。。這個文件沒說。。這裡繼續浪費時間。。。。。。

.

        /// <summary>
        /// 給報文簽名
        /// </summary>
        /// <param name="xmldoc">xml報文</param>
        /// <returns></returns>
        private static string signMessage(XmlDocument xmldoc)
        {
            string temp = "AttachedSign" + GlobalData.TranInfo["商戶號"] + xmldoc.OuterXml;
            int strLength = Encoding.UTF8.GetByteCount(temp);
            string tempSign = BCMSocket.GetData(strLength.ToString().PadLeft(8, '0') + temp);
            return tempSign.Substring(8);
        }

解籤的。同樣道理是要AttachedVerify開始到末尾的位元組長度。不是字元長度。。這裡文件沒仔細看。。。。

        /// <summary>
        /// 解簽報文
        /// </summary>
        /// <param name="signStr"></param>
        /// <returns></returns>
        public static XmlDocument UnSignMessage(string signStr)
        {
            string temp = "AttachedVerify" + signStr;
            int strLength = Encoding.UTF8.GetByteCount(temp);
            //int strLength = temp.Length;
            string tempSign = BCMSocket.GetData(strLength.ToString().PadLeft(8, '0') + temp);
            tempSign= tempSign.Substring(8);
            StringReader Reader = new StringReader(tempSign);
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(Reader);
            return xmlDoc;
        }

順便附上獲得指定標籤值的程式碼。

   private string getXMLInnerText(Dictionary<string, string> xmlNodeDic, string key)
        {
            if (xmlNodeDic.ContainsKey(key))
            {
                return xmlNodeDic[key];
            }

            return "";
        }

第三點:伺服器傳送接收程式碼

就寫一段代表性的,注意這裡用TCL連線。而且傳送和接收都用UTF-8編碼。我就是因為沒注意導致接收到的中文全是 “?” 號,當時還以為SOCKET出問題了。。。唉

 public class BCMSocket
    {
        public static string GetData(string sendStr)
        {
            string url = "127.0.0.1";   // URL也可以是(http://www.baidu.com/)這種形式
            int port = Convert.ToInt32(GlobalData.TranInfo["signPoint"]);    //埠

            BCMSocketHelper o = new BCMSocketHelper();  //建立新物件
            o.Connection(url, port);                //開啟遠端埠
            o.Send(sendStr);                     //傳送資料
            string rs = o.Recev();

            o.Dispose(); //銷燬物件
            return rs;
        }
    }

這是SOCKET的資料:https://www.cnblogs.com/feifeiwzh/articles/1267895.html