连载篇提前看
物流一站式查询之 TrackingMore 篇
物流一站式查询之顺丰接口篇
物流一站式查询之快递 100
前言
前两篇我们已经讲了 TrackingMore 和顺丰接口的场景应用和对接示例,本篇,将会对项目中如何使用快递 100 物流平台进行物流信息跟踪的对接进行一个全面详细的讲解.同样,我们会分为申请接入,物流信息订阅,物流消息推送,物流消息查询等几个步骤分别讲解.各位看官,请拿好你们的板凳和瓜子.我们要开始了,
接口申请
进入快递 100 官网 https://www.kuaidi100.com/
在快递接口 (API) 菜单中,我们可以看到接口申请这个菜单,点击进去会有免费版和企业版两种功能和资费介绍.
这里我们选择企业版,点击企业版,会要求填一些基本信息,我们按要求填完然后点击提交申请即可.
申请之后,有客服会通过联系方式联系所填号码,然后进行需求确认.这时候我们可以注册一个快递 100 的账号
注册完之后就可以进行登录了,登录之后在主页面,就可以看到再快递 100 平台中的账户余额情况,以及下面表格给出的可用的产品,服务等开通的状态 (具体开通流程和客服取得联系之后他会协助你完成的),如下图所示
开通各个接口是需要快递 100 那边进行审核的,审核通过之后会发邮件出来,附件里面会带有一些接口文档,截图如下:
其中 较为重要的是审核结果中会有一个分配好的 Key 密匙,请求接口的时候需要用到.所以需要妥善保管.
首先来看一下快递 100 给出的订阅和推送的流向示意图
物流订阅
拿到接口文档相关秘籍和查阅请求调用流程图之后,我们便可以进行开发了,下面是物流订阅的相关示例步骤:
2.1 订阅请求
发起方: 本服务用户,即贵公司
地址: http://www.kuaidi100.com/poll
通信协议: HTTP
请求类型: POST
字符集: utf-8
请求内容:
schema= json/xml (或者 xml, 选择 json 则推送也是 json,选择 xml 则推送也是 xml,默认是 json)
param=body
Body 格式 (json):
{
"company":"yuantong", // 订阅的快递公司的编码,一律用小写字母,见章五《快递公司编码》
"number":"12345678", // 订阅的快递单号,单号的最大长度是 32 个字符
"from":"广东省深圳市南山区", // 出发地城市
"to":"北京市朝阳区", // 目的地城市,到达目的地后会加大监控频率
"key":"*********", // 授权码,签订合同后发放
"parameters":{
"callbackurl":" http://www . 您的域名. com/kuaidi?callbackid=...",// 回调地址
"salt":"any string", // 签名用随机字符串(可选)
"resultv2":"1" // 添加此字段表示开通行政区域解析功能(仅对开通签收状态服务用户有效),见章 3.1《推送请求》
}
}
Body 格式 (xml):
<?xml version='1.0'encoding='UTF-8'?>
<orderRequest>
<company>yuantong</company> // 订阅的快递公司的编码,一律用小写字母,见章五《快递公司编码》
<number>123123123123</number> // 订阅的快递单号
<from> 北京市朝阳区东直门外大街 </from> // 出发地城市
<to> 广东省深圳市南山区科技园 </to> // 目的地城市,到达目的地后会加大监控频率
<key>**********</key> // 授权码,签订合同后发放
<parameters>
http://www . 你的域名. com/kuaidi/push?XXXXX=ZZZZ// 回调地址
<salt>any string</salt> // 签名用随机字符串(可选)
<resultv2>1</ resultv2> // 添加此字段表示开通行政区域解析功能(仅对开通签收状态服务用户有效),见章 3.1《推送请求》
</parameters>
</orderRequest>
①根据订阅请求文档编写请求方法,首先我们编写两个类,一个是快递订阅信息类,另一个是快递 100 返回信息类
/// <summary>
/// 快递订阅信息
/// </summary>
public class KuaiDiInput
{
/// <summary>
/// 快递单号
/// </summary>
public string ExpressNumber;
/// <summary>
/// 快递公司编号
/// </summary>
public string CompanyNumber;
/// <summary>
/// 收货地址
/// </summary>
public string Address;
/// <summary>
/// 回调接口Url
/// </summary>
public string CallBackUrl;
}
View Code
/// <summary>
/// 快递100查询公司返回信息
/// </summary>
public class KuaiDiOut
{
/// <summary>
/// 快递公司编码
/// </summary>
public string comCode;
/// <summary>
/// 内部字段
/// </summary>
public string Id;
/// <summary>
/// 内部字段
/// </summary>
public string noCount;
/// <summary>
/// 内部字段
/// </summary>
public string noPre;
/// <summary>
/// 内部字段
/// </summary>
public string startTime;
}
View Code
②编写快递 100 订阅接口请求类 KuaiDi100,此类中包含的请求方法如下
/// <summary>
/// 订阅快递单号
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static OperationResult Subscibe(KuaiDiInput input)
{
WebClient client = new WebClient();
NameValueCollection postVars =
new NameValueCollection();
String param = "";
param += "{";
param += "\"company\":\"" + input.CompanyNumber + "\",";
param += "\"number\":\"" + input.ExpressNumber + "\",";
param += "\"from\":\"\",";
param += "\"to\":\"" + TrimAddress(input.Address) + "\",";
param += "\"key\":\"" + ConfigHelper.GetKey("SendKey") + "\",";
param += "\"parameters\":{\"callbackurl\":\"" + input.CallBackUrl + "\"}";
param += "}";
postVars.Add("schema", "json");
postVars.Add("param", param);
byte[] byRemoteInfo = client.UploadValues("http://www.kuaidi100.com/poll", "POST", postVars);
string output = Encoding.UTF8.GetString(byRemoteInfo).ToLower();
if (GetValueFromJson(output, "result") != "true")
{
string message = GetValueFromJson(output, "message");
if (message.IndexOf("重复订阅") < 0)
{
return new OperationResult(message);
}
}
return new OperationResult();
}
View Code
方法的返回值是自定义的一个 OperationResult 类,当前框架业务操作结果 此类返回操作成功或者操作失败,类部分内容如下:
/// <summary>
/// 框架业务操作结果
/// </summary>
public class OperationResult
{
/// <summary>
/// 默认操作成功
/// </summary>
public OperationResult()
{
IsSuccess = true;
}
/// <summary>
/// 以操作失败信息实例操作结果
/// </summary>
/// <param name="failMessage">操作失败信息</param>
public OperationResult(string failMessage)
{
IsSuccess = false;
FailMessage = failMessage;
}
}
View Code
另外请求方法中的 GetValueFromJson 方法是表示从 Json 字符串中取出某个值,再前两篇文章中我们也提到过这个方法,这里再贴一下:
/// <summary>
/// 从json字符串中获取字段值
/// </summary>
/// <param name="json">json字符串</param>
/// <param name="field">要解析出值的字段</param>
/// <returns></returns>
private static string GetValueFromJson(string json, string field)
{
int start = json.IndexOf(field + "\":");
start += field.Length + 2;
int end = json.IndexOf(",", start);
if (end < 0)
{
end = json.IndexOf("}", start);
}
return json.Substring(start, end - start).Trim('"');
}
View Code
另外,请求方法中的地址我们使用了一个方法去除地址中的特殊字符,方法如下 ":
/// <summary>
/// 去除地址中的特殊字符
/// </summary>
/// <param name="address">地址</param>
/// <returns></returns>
private static string TrimAddress(string address)
{
if (String.IsNullOrEmpty(address))
{
return address;
}
return address.Replace("'", "").Replace("\\", "").Replace("/", "").Replace("\"", "").Replace("\n", "").Replace("\r", "").Replace("\t", "");
}
这样,我们请求方法就完成了,现在只剩下调用,一般项目中可以写一个服务,定时查询数据库,根据一些特定条件筛选,然后进行接口调用.调用示例如下:
OperationResult result = KuaiDi100.Subscibe(new KuaiDiInput() { ExpressNumber = item.ExpressNumber, Address = item.Address, CompanyNumber = item.CompanyNumber, CallBackUrl = "此处是回调地址" });
if (result.IsSuccess)
{
//订阅成功,记录一些状态
}else
{
//订阅失败,记录一些状态
}
订阅返回的接口示例我们看一下
2.2 订阅返回
由快递 100 直接通过订阅请求的 response 返回.
返回格式(json):
{
"result":"true",
"returnCode":"200",
"message":"提交成功"
}
返回格式(xml):
<?xml version='1.0'encoding='UTF-8'?>
<orderResponse>
<result>true</result>
<returnCode>200</returnCode>
<message> 订阅成功 </message>
</orderResponse>
result: "true" 表示成功,false 表示失败
returnCode:
200: 提交成功
701: 拒绝订阅的快递公司
700: 订阅方的订阅数据存在错误(如不支持的快递公司,单号为空,单号超长等)
600: 您不是合法的订阅者(即授权 Key 出错)
500: 服务器错误(即快递 100 的服务器出理间隙或临时性异常,有时如果因为不按规范提交请求,比如快递公司参数写错等,也会报此错误)
501: 重复订阅
订阅成功后,我们再快递 100 后台是可以看到订阅记录的,如下图
物流推送
那推送就比较好处理了,推送即是 当物流信息有发生变化时,快递 100 就会向请求订阅时所填的回调地址,发送此条变化的所有物流信息.推送请求示例如下 (body 太长了,这里就不贴出来了)
3.1 推送请求
发起方: 快递 100
请求地址: 在订阅请求中提供(即回调 servlet 的互联网地址)
通信协议: HTTP
请求类型: POST
字符集: utf-8
请求内容: param=body 或者 param=body&sign=signvalue
查看了推送请求之后,我们根据快递 100 的推送请求,我们先写出相关的返回结果模型 ModPushRequest
/// <summary>
/// 快递100传回快递结果模型
/// </summary>
public class ModPushRequest
{
/// <summary>
/// 监控状态相关消息,如:3天查询无记录,60天无变化
/// </summary>
public string message { set; get; }
/// <summary>
/// 包括got,sending,check三个状态,由于意义不大,已弃用,请忽略
/// </summary>
public string billstatus { set; get; }
/// <summary>
/// 监控状态:polling:监控中,shutdown:结束,abort:中止,updateall:重新推送.
/// 其中当快递单为已签收时status=shutdown,当message为"3天查询无记录"或"60天无变化时"status= abort ,对于stuatus=abort的状度,需要增加额外的处理逻辑,详见本节最后的说明
/// </summary>
public string status { set; get; }
/// <summary>
/// 最新查询结果,全量,倒序(即时间最新的在最前)
/// </summary>
public ModLastResult lastResult { set; get; }
}
View Code
其中 ModLastResult 是 快递 100 传回快递状态模型如下
/// <summary>
/// 快递100传回快递状态模型
/// </summary>
public class ModLastResult
{
/// <summary>
/// 消息体,请忽略
/// </summary>
public string message { set; get; }
/// <summary>
/// 快递单当前签收状态,包括0在途中,1已揽收,2疑难,3已签收,4退签,5同城派送中,6退回,7转单等7个状态
/// </summary>
public string state { set; get; }
/// <summary>
/// 快递单明细状态标记,暂未实现,请忽略
/// </summary>
public string condition { set; get; }
/// <summary>
/// 否签收标记,明细状态请参考state字段
/// </summary>
public string ischeck { set; get; }
/// <summary>
/// 快递公司编码,一律用小写字母
/// </summary>
public string com { set; get; }
/// <summary>
/// 快递单号
/// </summary>
public string nu { set; get; }
/// <summary>
/// 通讯状态,请忽略
/// </summary>
public string status { set; get; }
/// <summary>
/// 快递物流信息,时间到序
/// </summary>
public List<ModData> data { set; get; }
}
View Code
其中 ModData 是物流信息 如下
/// <summary>
/// 快递100传回快递记录模型
/// </summary>
public class ModData
{
/// <summary>
/// 快递物流内容
/// </summary>
public string context { set; get; }
/// <summary>
/// 快递原始时间
/// </summary>
public string time { set; get; }
/// <summary>
/// 快递格式化时间
/// </summary>
public string ftime { set; get; }
}
有了推送模型,那此时我们要做的就是接收快递 100 的请求数据即可,代码如下:
/// <summary>
/// 更新订单快递信息
/// </summary>
/// <param name="form"></param>
/// <returns></returns>
public ActionResult UpdateMessage(FormCollection form)
{
try
{
string json = form.Get("param");
JavaScriptSerializer serializer = new JavaScriptSerializer();
//将Json字符串转换为ModPushRequest类型对象
ModPushRequest pustRequest = serializer.Deserialize<ModPushRequest>(json);
//TODO
}
catch{}
}
以上我们就将收到的数据成功转换成了我们的模型数据,剩下的就是具体业务需求了,这个可以根据实际项目情况,做不同的处理.例如:TODO 可以 先拿到返回的快递单号
string number = pustRequest.lastResult.nu;
然后可以去查询数据库中找到此单号的订单信息.再循环物流信息
string senderMessage = "";
string lastMessage = "";
foreach (ModData item in pustRequest.lastResult.data)
{
//所有物流信息
senderMessage += item.ftime + " " + item.context + "<br/>";
}
if (pustRequest.lastResult.data.Count > 0)
{
//最近一条物流信息
lastMessage = pustRequest.lastResult.data[0].ftime + " " +
pustRequest.lastResult.data[0].context;
}
然后可以再根据不同的物流返回状态做不同的操作
// 快递单当前签收状态,包括0在途中,1已揽收,2疑难,3已签收,4退签,5同城派送中,6退回,7转单等7个状态
if (pustRequest.lastResult.state == "3")
{
//TODO
}
else if (pustRequest.lastResult.state == "4" || pustRequest.lastResult.state == "6")
{
//TODO
}
温馨提示,设计订单表的时候,可以多加三个字段,一个字段是订阅时间,一个是物流平台推送回来的时候推送时间,再一个是物流平台推送过来时的推送状态.可以记录用于后面物流数据分析.
物流消息查询
5,整体使用流程:
第一步,后台创建链接,调用: http://www.kuaidi100.com/applyurl?key=[]&com=[]&nu=[ ] ,调用后系统会返回一个 url 地址,如: http://www.kuaidi100.com/kuaidiresult?id=23 .
第二步:在要显示结果的页面添加一个 iframe 标签,将上述结果 url 地址传入该 iframe 标签的的 src 值,即可在该页面查看到结果(如果要实现系统自动地将结果 url 传入 iframe 标签的 src,请参考下面第五章),iframe 代码示范:
<iframe name="kuaidi100"src=" 结果 url 地址 "width="600"height="380"marginwidth="0"marginheight="0"hspace="0"vspace="0"frameborder="0"scrolling="no"></iframe>
使用场景,项目中的订单,我们一定不是每次都直接去调接口查询,那样太慢,效率也不高,只有部分,数据表中物流信息没有且平台订单不为空的时候,查询物流信息时,我们需要去实时调用查询接口,将数据返回出来.根据整体使用流程介绍,我们很容知道,是通过返回 html 绑定再 iframe 上实现的.实现如下:
前台页面 (传入快递公司对应的公司编码和物流单号)
ajaxGetContent("@Url.Action("ViewExpress")" + "?companyNumber=" + company + "&expressNumber=" + number, function (data) {
var d = dialog({
title: '物流最新跟踪',
content: data,
okValue: '确定',
ok: true,
});
d.show(obj);
});
Action
public ActionResult ViewExpress(string expressNumber, string companyNumber)
{
#region 快递100 获取方式
string url = "http://www.kuaidi100.com/applyurl?key=974498a9701a6c9b&com=" + companyNumber + "&nu=" +
expressNumber;
//初始化获取HTML动作
GetHtmlFromUrl getHtml = new GetHtmlFromUrl(url);
//获取请求的url中html字符串
getHtml.StartWork();
//数据绑定
ViewData.Model = getHtml.ResultHtml;
#endregion
}
其中初始化 html 方法如下:
/// <summary>
/// 初始化一个获取html动作
/// </summary>
/// <param name="requestUrl">要请求的url地址</param>
public GetHtmlFromUrl(string requestUrl)
{
ArgumentChecker.ThrowExceptionWhenStringIsNullOrEmpty(requestUrl, "requestUrl");
if (requestUrl.IndexOf("//") < 0)
{
requestUrl = "http://" + requestUrl;
}
RequestUrl = requestUrl;
}
获取请求 url 地址的 html 字符串方法如下:
/// <summary>
/// 开始获取请求url地址的html字符串
/// </summary>
public void StartWork()
{
WebRequest request = WebRequest.Create(RequestUrl);
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream, System.Text.Encoding.GetEncoding("UTF-8")))
{
ResultHtml = reader.ReadToEnd();
}
}
}
}
返回的 ViewExpress 视图如下
@model string
<iframe name="kuaidi100" src="@Model" width="600" height="380" marginwidth="0" marginheight="0" hspace="0" vspace="0" frameborder="0" scrolling="no"></iframe>
这样我们就按照文档中所说的将返回 html 呈现出来了
返回结果说明:
提交请求后,快递 100 会给您返回一个可以看到结果的 url 地址,如: http://www.kuaidi100.com/kuaidiresult?id=23 ,您直接访问或用 iframe 页调用该 url(调用方法见后面第四章),即可以看到结果.效果:
特别提醒:
因为 EMS,顺丰和申通偶尔会不稳定, 不稳定时会先显示验证码(如下图所示),所以请勿直接将这个页面直接解析成 JSON 等形式,否则会出错
至此,我们在通过快递 100 平台 完成了快递订阅,接收了快递消息的推送以及我们自主通过快递 100 接口查询最新的物流信息.
到这里,三篇关于快递接口的文章已经全部结束,文中给出的只是根据官方文档要求,编写的部分代码,可能不尽完善,能够优化的地方还有很多,大家能借鉴的地方借鉴一下就好~
End!
来源: https://www.cnblogs.com/zhangxiaoyong/p/8317251.html