前言
分享一篇关于在电商系统中同步物流轨迹到本地服务器的文章,当前方案使用了快递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群里