前言
分享一篇關於在電商系統中同步物流軌跡到本地服務器的文章,當前方案使用了快遞100做為數據來源接口,這個接口是收費的,不過提供的功能還是非常強大的,有專門的售后維護團隊。也有免費的方案,類似於快遞鳥,不過數據出現問題就涼涼了
正文
實現思路大概分為三大步:
第一步:提交訂閱信息到快遞100的接口
第二步:快遞100收到請求后會對回調地址進行跟蹤,將快遞信息推送給回調接口
第三步:回調接口收到Post推送的數據后,進行邏輯處理
注意:回調的地址建議單獨部署一個API項目,不要放在主程序下面;或者在提交訂閱時要求對回調進行簽名驗證。
下面附上詳細代碼:
Subscribe類

using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using WoT.Infrastructure.Helper.Xml; using WoT.Model.Inventory; using WoT.ViewModel.Dtos.Inventory; namespace WoT.SyscTraceSys { /// <summary> /// 訂閱物流軌跡 /// </summary> public class Subscribe { //拿到授權的Key private static string key = ConfigurationManager.AppSettings["SubscribeKey"]; //請求的url private static string reqUrl = "http://www.kuaidi100.com/poll"; //回調url private static string callbackurl = "http://你的域名/api/kd100/callback"; /// <summary> /// 發送訂閱指令 /// </summary> /// <param name="invoce">發貨單</param> /// <param name="shipperCode">快遞公司</param> /// <returns></returns> public static KD100Result SendPost(Invoice invoce, string shipperCode = "SF") { StringBuilder param = new StringBuilder(); KD100Result kdResult = new KD100Result(); param.Append("<?xml version='1.0' encoding='UTF-8'?>") .AppendFormat("<orderRequest>") .AppendFormat("<company>{0}</company>", GetCom(shipperCode)) .AppendFormat("<number>{0}</number>", invoce.LogisticCode) .AppendFormat("<from></from>") .AppendFormat("<to></to>") .AppendFormat("<key>{0}</key>", key) .AppendFormat("<parameters><callbackurl>{0}</callbackurl><resultv2>1</resultv2></parameters>", callbackurl) .Append("</orderRequest>"); NameValueCollection postvals = new NameValueCollection(); postvals.Add("schema", "xml"); postvals.Add("param", param.ToString()); try { using (WebClient wc = new WebClient()) { string rlt = System.Text.Encoding.UTF8.GetString(wc.UploadValues(reqUrl, "POST", postvals)); kdResult = XmlExpand.DESerializer<KD100Result>(rlt); } } catch (Exception ex) { return new KD100Result() { result = false, returnCode = 0, message = ex.Message }; } return kdResult; } /// <summary> /// 獲取com /// </summary> /// <param name="shipperCode"></param> /// <returns></returns> private static string GetCom(string shipperCode) { string com = "shunfeng"; switch (shipperCode) { case "EMS": com = "ems"; break; case "SF": com = "shunfeng"; break; case "STO": com = "shentong"; break; case "YD": com = "yunda"; break; case "YTO": com = "yuantong"; break; case "YZPY": com = "youzhengguonei"; break; case "ZJS": com = "zhaijisong"; break; case "ZTO": com = "zhongtong"; break; case "DBL": com = "debangwuliu"; break; case "JD": com = "debangwuliu"; break; default: break; } return com; } } }
GetCom()方法是獲取獲取快遞公司的標示編號,我在數據庫中只存了快遞簡稱,所以需要通過這種方式獲取,如果是存在數據庫的就可以直接從數據庫獲取了。
DESerializer()方法將xml字符串轉化為實體對象,關於實現的詳情在前面C#操作Xml樹的擴展類一節中有講到。
ConfigurationManager.AppSettings["SubscribeKey"];是讀取配置文件,獲取快遞100對商戶授權的Key,配置代碼如下:
在appSettings節點下添加

KD100Result類
/// <summary> /// 快遞100返回結果 /// </summary> [Serializable] [XmlType("orderResponse")] public class KD100Result { /// <summary> /// /// </summary> [XmlElement("result")] public bool result { get; set; } /// <summary> /// /// </summary> [XmlElement("returnCode")] public int returnCode { get; set; } /// <summary> /// /// </summary> [XmlElement("message")] public string message { get; set; } }
回調接口Action

/// <summary> /// /// </summary> /// <returns></returns> [HttpPost] [Route("callback")] public void callback() { StringBuilder sb = new StringBuilder(); DateTime now = DateTime.Now; pushResponse push = new pushResponse() { Result = false, ReturnCode = 404, Message = "沒有拉取到相關數據" }; HttpContext context = HttpContext.Current; if (!context.Request.RequestType.ToUpper().Equals("POST")) { context.Response.Write(string.Format("<?xml version='1.0' encoding='UTF-8'?><pushResponse><result>{0}</result><returnCode>{1}</returnCode><message>{2}</message></pushResponse>", false, 0, "請使用POST提交")); context.Response.End(); return; } try { sb.Clear(); var stream = context.Request.InputStream; string param = ReadStream(stream); if (string.IsNullOrEmpty(param)) { context.Response.Write(string.Format("<?xml version='1.0' encoding='UTF-8'?><pushResponse><result>{0}</result><returnCode>{1}</returnCode><message>{2}ee</message></pushResponse>", push.Result, push.ReturnCode, push.Message)); context.Response.End(); return; } Dictionary<string, string> dic = new Dictionary<string, string>(); string[] sp1 = param.Split('&'); foreach (string s in sp1) { int splIdx = s.IndexOf('='); string key = s.Substring(0, splIdx); string value = s.Substring(splIdx + 1); dic.Add(key.Trim(), value.Trim()); } string cbxml = HttpUtility.UrlDecode(dic["param"], Encoding.UTF8); using (ILogisticsTraceService _Service = CoreServiceFactory.Used.Build<ILogisticsTraceService>()) { push = _Service.PushLogisticsTrace(cbxml); } sb.Append("<?xml version='1.0' encoding='UTF-8'?>") .AppendFormat("<pushResponse><result>{0}</result>", push.Result) .AppendFormat("<returnCode>{0}</returnCode>", push.ReturnCode) .AppendFormat("<message>{0}</message>", push.Message) .Append("</pushResponse>"); stream.Close(); context.Response.Write(sb.ToString()); context.Response.End(); } catch (Exception) { context.Response.Write(string.Format("<?xml version='1.0' encoding='UTF-8'?><pushResponse><result>{0}</result><returnCode>{1}</returnCode><message>{2}</message></pushResponse>", false, 0, "服務器處理錯誤")); } }
有需要源碼的朋友可以掃描下方二維碼加入QQ群,我會把源碼分享在QQ群里