海关 实时数据 企业联调接口 开发步骤与概要
写这个文章前, 先呐喊几声, 一吐心中不快, 诺大的中国海关, 连个指导都没有, 写的文档与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
用其它语言来写也行的, 只是要把websocket send的内容改为json, 一模一样的对比一下。
这里取得了加签的内容, 就可以拼凑成返回海关的报文。 记得这里只是拼接报文成功, 你还得联系海关二位员工, 张丁二将, 把上面4.4得到的证书与编号发给他们, 然后请他们帮助你设置海关测试环境。
最后说一下, 本人2003年中山大学毕业, 经过无数次亿万级的系统开发与构架,像香港证券交易, 香港电讯短信通道这些平台, 每秒都是几百几千请求, 面对这小小的不成文不成档的奇怪接口, 也曾发火几次, 希望这文章对大家有用!
同时也建议, 各位开发工程师, 如果自己有接口对外的, 希望能认真写写详细的文档, 因为自己做的东西可以感觉很简单, 外人看来还是有复杂度的, 像这样接口, 明明涉及硬件软件, 他文档里一句不提, 最重要的signvalue得来, 居然没详细的方法, 直接用123来代替, 真的是只有中国政府才能做出这么伟大的事业, 万望各位开发工程师引以为介, 从大家做起, 不要让简单的事复杂起来。