1. 程式人生 > >海關 實時資料 企業聯調介面 開發步驟與概要

海關 實時資料 企業聯調介面 開發步驟與概要

寫這個文章前, 先吶喊幾聲, 一吐心中不快, 諾大的中國海關, 連個指導都沒有, 寫的文件與demo, 100個人有99.9個人不懂, 還有0.1個人一次能懂的都算是神童, 

 

首先, 中國海關資料中心, 經過這個介面的實現, 我感覺到政府的無能, 也感覺到科技不要說晶片, 就連最簡單的1+1=2的程式在政府部門都寫不好, 也不知這海關資訊資料中心領導怎混出來的,

 

如果中國找不到這樣的人, 如果有人認得中國海關署長的, 就幫我推薦一下, 可能我技術不算頂峰高手, 但寫個文件或指導教程, 絕對能讓50%的人一次性看得明白。 諾大的中國海關資料中心, 連個技術指導都請不起, 可憐呀, 錢都哪去了?

 

如果能罵人的, 我接著寫, 不過還是提介文明, 就不吐了。

 

正題啦:

第一步:

看二個公告

http://www.customs.gov.cn/customs/302249/302266/302267/2134975/index.html 165號

http://www.customs.gov.cn/customs/302249/302266/302267/2155884/index.html 179號

 

第二步:

下載179號公告文件, 文件包括下面

 

第三步:

開啟“海關跨境電商進口版統一資訊化系統平臺數據實時獲取介面(試行)”, 請看1.6.1.1 這裡得知, 需要寫一個介面, 讓海關請求帶三個引數OrderNo, sessionID,serviceTime,  把這三個引數存放起來,  可以是訊息佇列, 可以是資料庫, 總之你能再次找得到就行。

 

第四步: 

既然在第三步接收到海關請求的內容也存放起來了, 總得處理並把他們想要的資料返回給海關, 這裡就介紹怎得到需要返回的資料, 最關鍵的一步, 請看1.6.2.2, 訂單,商品,支付這些資料, 可能通過OrderNo在你們電商平臺得到, 最麻煩的就是CertNo, signValue這二個引數,

官方文件把最維得到的引數用123來代替, 我感覺他們是小學生水平。

4.1 得去公司找到一個海關登入的IC卡,有一個讀卡器, 一般有二個卡(法人卡,操作員卡),記得把操作員卡接到讀卡器裡, 不能是法人卡,這個十分注意。

4.2 下載海關控制元件安裝包, 開啟這個網址 http://ceb1.chinaport.gov.cn/  , 點 跨境電商進口版, 認真查詢“首次登入 需要下載控制元件”, 點選下載 EportClientSetup_V1.5.5.exe, 請看清楚下載的檔名是不是這個, 這也是十分重要, 如果你千百次對比沒錯後, 請安裝它, 安裝完成電腦螢幕右下角會有一個控制元件啟動提醒, 桌面也有一個快捷方式“中國電子口岸客戶端控制元件 重新啟動”。 

4.3 把4.1步裡面找到的讀卡器接上電腦, 記得這個電腦要安裝了海關控制元件的, 千萬不要搞成, A電腦裝了控制元件, 把這讀卡器接B電腦上。 如果讀卡器出現綠燈, 說明讀卡器與卡都沒問題, 如果是燈不亮或紅燈, 不好意思, 你的卡與讀卡器可能有問題了,得找另一個卡與讀卡器再試。

4.4 當環境設定好了, 就需要取CertNo, 證書這些, 下載這個讀取編號與證書的工具: https://pan.baidu.com/s/1xo0AcZZ4QZDeAu2DHOEQjg   提取碼: cfpp , 解壓開啟SignTool.exe

點選步驟:開啟卡, 如果出現開啟卡成功, 恭喜你, 又前進一步,在驗證口令後面的文字框輸入設定的密碼, 這個密碼得問一下你們公司掌管卡的人,如果錄入後點擊 驗證口令 提示 驗證口令成功, 又恭喜你前進一步, 點選“獲取證書”, 成功的會得到後面文字框裡的一串文字, 注意這個文字好長好長, 得小心從文字框裡最上方拉到最下方, 很多人沒拉到底, 造成證書錯誤, 當你選擇全部後複製出來, 用記事本原封不動的儲存, 改字尾名為.cer, 這樣就成他們口中所說的證書了, 再點選證書序列號,會得到一個證書編號。

 

發給海關的丁鑫, 並登記企業名稱, 企業聯絡人等資訊, 總之找他就行了, 怎找呢, 看文章最後一個圖。

 

到這裡, 只差一個signValue這個千奇百怪的東西了。

 

第五步:

誓取signValue這個海關奇怪設計失敗貨, 一千種方法都可以簡單得到, 他們設計出一個最麻煩最不穩定的取得方法, 小學生水平, 沒辦法。

5.1 首先你要看那個"海關跨境電商進口版統一資訊化系統平臺數據實時獲取介面(試行)"文件, 通過OrderNo把你訂單資訊,商品資訊,支付資訊拼成這樣的Json, 你也可以用這個來測試, 測試通了, 再取訂單來拼接, 如果後面傳送得到資料格式有誤, 你就得一個字元一個字元的去對, 是否一模一樣。

"sessionID":"fe2374-8fnejf97-55616242"||"payExchangeInfoHead":"{"guid":"9D55BA71-55DE-41F4-8B50-C36C83B3B419","initalRequest":"https://openapi.alipay.com/gateway.do?timestamp=2013-01-0108:08:08&method=alipay.trade.pay&app_id=13580&sign_type=RSA2&sign=ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE&version=1.0&charset=GBK","initalResponse":"ok","ebpCode":"3301963K69","payCode":"312226T001","payTransactionId":"2018121222001354081010726129","totalAmount":100,"currency":"142","verDept":"3","payType":"1","tradingTime":"20181212041803","note":"批量訂單,測試訂單優化,生成多個so訂單"}"||"payExchangeInfoLists":"[{"orderNo":"SO1710301150602574003","goodsInfo":[{"gname":"lhy-gnsku3","itemLink":"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999761&shopId=453"},{"gname":"lhy-gnsku2","itemLink":"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999760&shopId=453"}],"recpAccount":"OSA571908863132601","recpCode":"","recpName":"YUNJIHONGKONGLIMITED"}]"||"serviceTime":"1544519952469"

得到了這段拼接字元, 就是為了得到signValue, 所以一個字元也不能出錯, 不然取不到正確的加簽返回值。

 

5.2 這裡最主要的就是通過websocket取得加簽結果

我這裡寫的是C#版的, Java版的我是向天虹張大工程師那得到的,在這裡十分感謝天虹張, 希望大家能多去天虹商場逛逛, 並感謝他們員工的大無畏精神, 和中國海關對比, 真的是像天虹浩月對中國海關的螢火

Java 天虹張工版下載地址: https://pan.baidu.com/s/1beifsbtA7fXmi4vJ3c2Kjw 提取碼: jdev    [不知我放在這裡, 天虹張工會不會介意, 如果不同意的我刪掉],  為了各電商平臺能快速完成,先對張工說十分抱歉,。

 

記得一個前提, websocket的地址就是你裝有控制元件,插有卡的那個電腦的IP地址, 例如:ws://127.0.0.1:61232, 這是我在開發時, 在我自己的電腦上裝有控制元件插有卡, 得來的websocket地址。

 

C# 版, 現在大家多用win7, win7不支援ClientWebSocket, 所以我使用了第三方包,WebSocket4Net, 在VS2015 NuGet上面直接安裝, 最終寫出最簡單的明瞭取得加簽返回值

 

using System;
using System.Text;
using WebSocket4Net;
using SuperSocket.ClientEngine;

namespace ConsoleApp
{
    public class Program
    {
        static WebSocket websocket = new WebSocket("ws://127.0.0.1:61232");

        public static void Main(string[] args)
        {
            try
            {                
                websocket.Opened += new EventHandler(websocket_Opened);
                websocket.Error += new EventHandler<ErrorEventArgs>(websocket_Error);
                websocket.Closed += new EventHandler(websocket_Closed);
                websocket.MessageReceived += new EventHandler<MessageReceivedEventArgs>(websocket_MessageReceived);
                websocket.Open();                

                Console.WriteLine("");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadLine();
        }

        private static void websocket_Opened(object sender, EventArgs e)
        {
            Console.WriteLine("websocket opened!" + DateTime.Now.ToString());
        }

        private static void websocket_Error(object sender, ErrorEventArgs e)
        {
            Console.WriteLine("websocket error!");
            Console.WriteLine("Error:" + e.Exception.Message.ToString());
        }

        private static void websocket_Closed(object sender, EventArgs e)
        {
            Console.WriteLine("websocket closed!" + DateTime.Now.ToString());
        }

        private static void websocket_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            Console.WriteLine("websocket message received!");
            string strMessaged = e.Message.ToString().Trim();
            if (strMessaged.Contains("握手成功"))
            {
                StringBuilder PostJson = new StringBuilder();
                PostJson.Append("\"sessionID\":\"fe2374-8fnejf97-55616242\"||\"payExchangeInfoHead\":\"{\"guid\":\"9D55BA71-55DE-41F4-8B50-C36C83B3B419\",\"initalRequest\":\"https://openapi.alipay.com/gateway.do?timestamp=2013-01-0108:08:08&method=alipay.trade.pay&app_id=13580&sign_type=RSA2&sign=ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE&version=1.0&charset=GBK\",\"initalResponse\":\"ok\",\"ebpCode\":\"3301963K69\",\"payCode\":\"312226T001\",\"payTransactionId\":\"2018121222001354081010726129\",\"totalAmount\":100,\"currency\":\"142\",\"verDept\":\"3\",\"payType\":\"1\",\"tradingTime\":\"20181212041803\",\"note\":\"批量訂單,測試訂單優化,生成多個so訂單\"}\"||\"payExchangeInfoLists\":\"[{\"orderNo\":\"SO1710301150602574003\",\"goodsInfo\":[{\"gname\":\"lhy-gnsku3\",\"itemLink\":\"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999761&shopId=453\"},{\"gname\":\"lhy-gnsku2\",\"itemLink\":\"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999760&shopId=453\"}],\"recpAccount\":\"OSA571908863132601\",\"recpCode\":\"\",\"recpName\":\"YUNJIHONGKONGLIMITED\"}]\"||\"serviceTime\":\"1544519952469\"");

                string strJson = PostJson.ToString();

                string strSendData0 = "{\"_method\":\"cus-sec_SpcSignDataAsPEM\",\"_id\":1,\"args\":{\"inData\":\"" + strJson.Replace("\"","\\\"") + "\",\"passwd\":\"66666666\"}}";
                //string strSendData1 = "{\"_method\":\"cus-sec_SpcSignDataAsPEM\",\"_id\":1,\"args\":{\"inData\":\"\\\"sessionID\\\":\\\"1dd44ea3-202a-43e7-87a5-6d82ca3fce4f\\\"||\\\"payExchangeInfoHead\\\":\\\"{\\\"guid\\\":\\\"9D55BA71-55DE-41F4-8B50-C36C83B3B419\\\",\\\"initalRequest\\\":\\\"https://openapi.alipay.com/gateway.do?timestamp=2013-01-0108:08:08&method=alipay.trade.pay&app_id=13580&sign_type=RSA2&sign=ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE&version=1.0&charset=GBK\\\",\\\"initalResponse\\\":\\\"ok\\\",\\\"ebpCode\\\":\\\"xxxxxxxx\\\",\\\"payCode\\\":\\\"312226T001\\\",\\\"payTransactionId\\\":\\\"2018121222001354081010726129\\\",\\\"totalAmount\\\":100,\\\"currency\\\":\\\"142\\\",\\\"verDept\\\":\\\"3\\\",\\\"payType\\\":\\\"1\\\",\\\"tradingTime\\\":\\\"20181212041803\\\",\\\"note\\\":\\\"批量訂單,測試訂單優化,生成多個so訂單\\\"}\\\"||\\\"payExchangeInfoLists\\\":\\\"[{\\\"orderNo\\\":\\\"SO1710301150602574003\\\",\\\"goodsInfo\\\":[{\\\"gname\\\":\\\"lhy-gnsku3\\\",\\\"itemLink\\\":\\\"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999761&shopId=453\\\"},{\\\"gname\\\":\\\"lhy-gnsku2\\\",\\\"itemLink\\\":\\\"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999760&shopId=453\\\"}],\\\"recpAccount\\\":\\\"OSA571908863132601\\\",\\\"recpCode\\\":\\\"\\\",\\\"recpName\\\":\\\"YUNJIHONGKONGLIMITED\\\"}]\\\"||\\\"serviceTime\\\":\\\"1544519952469\\\"\",\"passwd\":\"66666666\"}}";
                //string strSendData2 = "";
                
                //Console.WriteLine(strSendData0);
                //Console.WriteLine("------------------------------------------");
                //Console.WriteLine(strSendData1);
                websocket.Send(strSendData0);
            }
            else
            {
                Console.WriteLine(strMessaged);
            }
            websocket.Close();
        }
    }
}
View Code

 

得到的返回值是如圖,data就是加簽的signValue, 起快把奇怪貨關起來, 我在海關微信群裡面, 無數工程師為了得到這個, 花上好幾天還沒有頭緒。 

 

用其它語言來寫也行的, 只是要把websocket send的內容改為json,  但傳送的內容得一模一樣, 這段是張工發給我的傳送給websocket加簽的內容。 看清楚必須格式一模一樣, 提示\\\sessionID\\\, 看清楚這個。

"{\"_method\":\"cus-sec_SpcSignDataAsPEM\",\"_id\":1,\"args\":{\"inData\":\"\\\"sessionID\\\":\\\"1dd44ea3-202a-43e7-87a5-6d82ca3fce4f\\\"||\\\"payExchangeInfoHead\\\":\\\"{\\\"guid\\\":\\\"9D55BA71-55DE-41F4-8B50-C36C83B3B419\\\",\\\"initalRequest\\\":\\\"https://openapi.alipay.com/gateway.do?timestamp=2013-01-0108:08:08&method=alipay.trade.pay&app_id=13580&sign_type=RSA2&sign=ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE&version=1.0&charset=GBK\\\",\\\"initalResponse\\\":\\\"ok\\\",\\\"ebpCode\\\":\\\"xxxxxxxx\\\",\\\"payCode\\\":\\\"312226T001\\\",\\\"payTransactionId\\\":\\\"2018121222001354081010726129\\\",\\\"totalAmount\\\":100,\\\"currency\\\":\\\"142\\\",\\\"verDept\\\":\\\"3\\\",\\\"payType\\\":\\\"1\\\",\\\"tradingTime\\\":\\\"20181212041803\\\",\\\"note\\\":\\\"批量訂單,測試訂單優化,生成多個so訂單\\\"}\\\"||\\\"payExchangeInfoLists\\\":\\\"[{\\\"orderNo\\\":\\\"SO1710301150602574003\\\",\\\"goodsInfo\\\":[{\\\"gname\\\":\\\"lhy-gnsku3\\\",\\\"itemLink\\\":\\\"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999761&shopId=453\\\"},{\\\"gname\\\":\\\"lhy-gnsku2\\\",\\\"itemLink\\\":\\\"http://m.yunjiweidian.com/yunjibuyer/static/vue-buyer/idc/index.html#/detail?itemId=999760&shopId=453\\\"}],\\\"recpAccount\\\":\\\"OSA571908863132601\\\",\\\"recpCode\\\":\\\"\\\",\\\"recpName\\\":\\\"YUNJIHONGKONGLIMITED\\\"}]\\\"||\\\"serviceTime\\\":\\\"1544519952469\\\"\",\"passwd\":\"11111111\"}}"

 

這裡取得了加簽的內容, 就可以拼湊成返回海關的報文。 記得這裡只是拼接報文成功, 你還得聯絡海關二位員工, 張丁二將, 把上面4.4得到的證書與編號發給他們, 然後請他們幫助你設定海關測試環境。 

 

 

最後說一下, 本人2003年中山大學畢業, 經過無數次億萬級的系統開發與構架,像香港證券交易, 香港電訊簡訊通道這些平臺, 每秒都是幾百幾千請求,  面對這小小的不成文不成檔的奇怪介面, 也曾發火幾次, 希望這文章對大家有用!

 

同時也建議, 各位開發工程師, 如果自己有介面對外的, 希望能認真寫寫詳細的文件, 因為自己做的東西可以感覺很簡單, 外人看來還是有複雜度的, 像這樣介面, 明明涉及硬體軟體, 他文件裡一句不提, 最重要的signvalue得來, 居然沒詳細的方法, 直接用123來代替, 真的是隻有中國政府才能做出這麼偉大的事業, 萬望各位開發工程師引以為介, 從大家做起, 不要讓簡單的事複雜起來。