快速集成快递物流轨迹查询功能

前沿

近年来,随着互联网的发展,各个行业都在用新的技术、新的观念为自己的发展打下坚实的基础,如今网络已经渗透到了人们的日常生活中,网上购物成了大家喜爱的方式。各类商城、APP、小程序等应用不断涌现,涉及各行各业,都在争抢成为人们网上购物的载体。网上购物物流是必不可少的一环,这些应用是如何解决物流信息系统化的,让消费者方便快捷的了解物品的实时轨迹信息和系统内部流程无阻碍自动流转?我认为有两种途径可达成,第一种是自建物流体系,逐个跟物流公司对接,设计符合自身的产品解决问题,这种方案的优点是灵活性非常高,高度契合公司系统,缺点也很明显,每家公司接口标准都不一样,需要懂物流的人抽象设计,接入难度大、耗时长、成本高、后期的维护成本也高。第二种是找一家第三方聚合物流平台接入即可,如:快递鸟、快递100、快递网等。物流平台对物流和电商两端的需求研究更深入,产品设计得更简单,对接更快捷,更重要的一点是只需一次接入即可使用平台支持的所有快递物流公司,开发周期短,后期维护成本低,缺点是这些平台都是标准接口,灵活性稍低,接口调用量大时需支付接口调用服务费,各家平台的收费标准都不一样,可登录其官网了解详情,下面为大家介绍如何接入快递鸟快递物流查询API。

应用场景

综合类电商平台、垂直类电商平台、小程序、ERP系统、工具等应用都可使用。

如电商平台在订单管理页面可查看物流轨迹信息

小程序通过扫码查看快递行踪

接入步骤

申请账号-->获取用户ID和Key-->申请开通套餐-->按要求对接,联调测试-->正式投产

1、申请账号和开通套餐

访问快递鸟注册页面进行账号注册,按页面提示,完成账号注册和完善资料,账号注册成功后可在用户中心查看获得用户ID和Key,同时在用户中心顶部点击申请开通套餐,这样子对接前期准备工作就完成了,使用ID和Key即可进行调用。

2、技术对接

访问快递鸟文档中心下载技术对接文档,快递鸟产品很多,选择适合自己的产品,根据文档参数对接即可。需要注意的是,对接过程如果遇到签名校验不过的问题,这时可查看生成验签的方式是否与文档一致,生成的验签是否存在大小写的问题,快递鸟的验签生成方式为:(请求内容(未编码)+ApiKey)进行MD5加密,然后Base64编码,最后进行URL(utf-8)编码。好了,不啰嗦了,直接上代码,如需对接的产品与示例不同只需更改requestType和应用级参数即可。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace KuaiDiChaXun
{
    /// <summary>
    /// 快递查询处理类
    /// </summary>
    public class KuaiDiChaXunBLL
    {
        #region 固定参数,实际项目中可写在配置文件中,方便修改
        string url = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";//请求url,正式环境
        string eBusinessID = "1257157";//用户ID,此ID仅作演示使用,实际调用需换成自己的ID,登录快递鸟官网会员中心获取
        string apiKey = "F201358A-513B-4237-98D6-67DE7EA75BA3";//用户秘钥,此秘钥仅作演示使用,实际调用需换成自己的秘钥,登录快递鸟官网会员中心获取        
        #endregion

        /// <summary>
        /// 查询快递路由轨迹
        /// </summary>
        /// <param name="shipperCode">快递公司编码</param>
        /// <param name="waybillCode">运单号</param>
        /// <param name="phoneNo">收/寄件人手机号后4位,SF必填</param>
        /// <returns></returns>
        public string SearchRoute(string shipperCode, string waybillCode, string phoneNo)
        {
            if (string.IsNullOrEmpty(shipperCode))
            {
                return "请输入快递公司编码";
            }
            if (string.IsNullOrEmpty(waybillCode))
            {
                return "请输入运单号";
            }
            if (string.IsNullOrEmpty(phoneNo) && shipperCode == "SF")
            {
                return "SF必填收/寄件人手机号后4位";
            }
            string result = string.Empty;
            //组装应用级参数,此Demo使用最少参数,更多参数参考技术文档
            string requestData = "{'ShipperCode':'" + shipperCode + "','LogisticCode':'" + waybillCode + "'}";
            if (shipperCode == "SF")//顺丰需收/寄件人手机号后4位
            {
                requestData = "{'ShipperCode':'" + shipperCode + "','LogisticCode':'" + waybillCode + "','CustomerName':'" + phoneNo + "'}";
            }
            //把(jsonStr+APIKey)进行MD5加密
            string md5Str = MD5(requestData + apiKey, "UTF-8");
            //把md5Str 进行Base64编码
            string base64Str = base64(md5Str, "UTF-8");
            //进行URL编码 (utf-8),最终得到签名串
            string dataSign = HttpUtility.UrlEncode(base64Str, Encoding.UTF8);
            //请求接口指令
            string cmd = "8001";
            //组装系统级参数
            string postData = "RequestData=" + HttpUtility.UrlEncode(requestData, Encoding.UTF8) + "&EBusinessID=" + eBusinessID + "&RequestType="+ cmd + "&DataSign=" + dataSign + "&DataType=2";
            //发起请求
            HttpHelper helper = new HttpHelper();
            HttpRequestEntity response = helper.Request(url, postData);
            if (response.IsSuccess == 0)
            {
                result = response.ResponseContent;
                //拿到结果后进行后续业务操作
            }
            else
            {
                result = "请求异常";
                //记录错误信息及后续业务补偿
            }
            return result;
        }

        ///<summary>
        /// 字符串MD5加密
        ///</summary>
        ///<param name="str">要加密的字符串</param>
        ///<param name="charset">编码方式</param>
        ///<returns>密文</returns>
        public string MD5(string str, string charset)
        {
            byte[] buffer = Encoding.GetEncoding(charset).GetBytes(str);
            try
            {
                System.Security.Cryptography.MD5CryptoServiceProvider check;
                check = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] somme = check.ComputeHash(buffer);
                string ret = "";
                foreach (byte a in somme)
                {
                    if (a < 16)
                        ret += "0" + a.ToString("X");
                    else
                        ret += a.ToString("X");
                }
                return ret.ToLower();
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// base64编码
        /// </summary>
        /// <param name="str">内容</param>
        /// <param name="charset">编码方式</param>
        /// <returns></returns>
        public string base64(string str, string charset)
        {
            return Convert.ToBase64String(Encoding.GetEncoding(charset).GetBytes(str));
        }
    }
}

HTTP封装类代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace KuaiDiChaXun
{
    public class HttpHelper : IDisposable
    {
        private bool _disposable = false;
        /// <summary>
        /// 请求编码格式默认utf-8;
        /// </summary>
        public Encoding HtmlEncoding = Encoding.UTF8;
        /// <summary>
        /// 请求时间
        /// </summary>
        public int Timeout = 5000;

        public CookieContainer Cookies = null;
        /// <summary>
        /// 是否记录Cookies
        /// </summary>
        public bool IsRecordCookie = false;

        public string ContentType = "application/x-www-form-urlencoded";

        public string AcceptLanguage = "en-US, en; q=0.8, zh-Hans-CN; q=0.5, zh-Hans; q=0.3";

        public string KeepAlive = "Keep-Alive";

        public string Accept = "*/*";

        private const string UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240";
        
        public HttpHelper()
        {
            //允许最大连接数
            ServicePointManager.DefaultConnectionLimit = 512;
        }        

        /// <summary>
        /// 基本请求方法
        /// </summary>
        /// <param name="requestType"></param>
        /// <param name="url"></param>
        /// <param name="requestData"></param>
        /// <returns></returns>
        private HttpRequestEntity BaseRequest(RequestType requestType, string url, string requestData)
        {
            var result = new HttpRequestEntity { IsSuccess = 0 };

            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException("请求Url不能为空值");

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();            
            HttpStatusCode statusCode = HttpStatusCode.OK;
            if (IsRecordCookie)
                Cookies = new CookieContainer();
            Stream requestStream = null;
            StreamReader streamReader = null;

            HttpWebRequest webRe = null;
            HttpWebResponse webPos = null;
            try
            {
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                    webRe = WebRequest.Create(url) as HttpWebRequest;
                    webRe.ProtocolVersion = HttpVersion.Version10;
                }
                else
                {
                    webRe = (HttpWebRequest)WebRequest.Create(url);
                }

                webRe.Headers.Add("Accept-Language", AcceptLanguage);
                webRe.Headers.Add("Keep-Alive", KeepAlive);
                webRe.UserAgent = UserAgent;
                webRe.Accept = Accept;
                webRe.Timeout = Timeout;
                webRe.ReadWriteTimeout = Timeout;
                webRe.CookieContainer = Cookies;

                if (requestType == RequestType.Post)
                {
                    webRe.ContentType = string.Format("{0}; {1}", ContentType, HtmlEncoding.BodyName);
                    byte[] datas = HtmlEncoding.GetBytes(requestData);
                    webRe.Method = "POST";
                    webRe.ContentLength = datas.Length;
                    webRe.MaximumResponseHeadersLength = -1;
                    requestStream = webRe.GetRequestStream();
                    requestStream.Write(datas, 0, datas.Length);
                    requestStream.Flush();
                    requestStream.Close();
                }
                else
                    webRe.Method = "GET";

                webPos = (HttpWebResponse)webRe.GetResponse();                
                statusCode = webPos.StatusCode;
                result.ResponseLength = webPos.ContentLength;
                result.ResponseEncodingName = webPos.ContentEncoding;

                requestStream = webPos.GetResponseStream();
                if (webPos.StatusCode == HttpStatusCode.OK)
                {
                    result.IsSuccess = 0;

                    if (requestStream != null)
                    {
                        streamReader = new StreamReader(requestStream, HtmlEncoding);
                        result.ResponseContent = streamReader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = 1;
                result.ResponseContent = ex.Message;
            }
            finally
            {
                if (requestStream != null)
                {
                    requestStream.Close();
                    requestStream.Dispose();
                }

                if (streamReader != null)
                {
                    streamReader.Close();
                    streamReader.Dispose();
                }

                webRe.Abort();
                if (webPos != null)
                    webPos.Close();

            }
            stopwatch.Stop();
            double elapseTime = stopwatch.Elapsed.TotalMilliseconds;//计算请求耗时
            return result;
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }

        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <returns></returns>
        public HttpRequestEntity Request(string url)
        {
            return BaseRequest(RequestType.Get, url, string.Empty);
        }

        /// <summary>
        /// Post请求
        /// </summary>
        /// <param name="url">请求地址Url</param>
        /// <param name="requestData">请求内容参数</param>
        /// <returns></returns>
        public HttpRequestEntity Request(string url, string requestData)
        {
            return BaseRequest(RequestType.Post, url, requestData);
        }

        ~HttpHelper()
        {
            Dispose(false);
        }

        #region IDisposable 成员

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (this._disposable)
                return;

            if (disposing)
            {

            }

            _disposable = true;
        }

        #endregion
    }

    /// <summary>
    /// HttpHelper请求方式
    /// </summary>
    public enum RequestType
    {
        /// <summary>
        /// Get请求
        /// </summary>
        Get,
        /// <summary>
        /// Post请求
        /// </summary>
        Post
    }

    /// <summary>
    /// HttpHelper请求时返回实体
    /// </summary>
    public class HttpRequestEntity
    {
        /// <summary>
        /// 请求是否成功 0-成功(返回Http状态码200) 1-失败(出现异常)
        /// </summary>
        public int IsSuccess { get; set; }
        /// <summary>
        /// 请求返回内容
        /// </summary>
        public string ResponseContent { get; set; }
        /// <summary>
        /// 请求返回内容长度
        /// </summary>
        public long ResponseLength { get; set; }
        /// <summary>
        /// 请求返回编码类型
        /// </summary>
        public string ResponseEncodingName { get; set; }
    }
}

调用示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KuaiDiChaXun
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                Console.WriteLine("请输入快递公司编码");
                string shipperCode = Console.ReadLine();

                Console.WriteLine("请输入运单号");
                string waybillCode = Console.ReadLine();

                Console.WriteLine("请输入收/寄件人手机号后4位,SF必填");
                string phone = Console.ReadLine();

                KuaiDiChaXunBLL bll = new KuaiDiChaXunBLL();
                string result = bll.SearchRoute(shipperCode, waybillCode, phone);
                Console.WriteLine("执行结果如下:");
                Console.WriteLine(result);
                Console.WriteLine("------------------");
                Console.WriteLine("------本次查询结束,按任意键继续,退出请输入exit------------");
                string cmd = Console.ReadLine().ToLower();
                if (cmd == "exit")
                {
                    return;
                }
            }
        }
    }
}

运行查看效果

以上是接入快递鸟快递查询接口示例代码,源码下载


如果对您有帮助劳烦帮忙点个赞,收藏关注一下,可以相互学习共同进步。

posted @ 2022-09-06 17:23  华小睿  阅读(639)  评论(0编辑  收藏  举报