引子
最近根據業務的一些需求,是以放棄從快遞鳥對接去電子面單,轉而直接對接韻達開發平台:
http://open.yundasys.com/,中間踩了一些坑,借此做了一個小案例給大夥,瞅瞅,若有需改進之處,還請指出!!!
廢話不多數:首先咱先對韻達的一些接口參數了解清楚:
當然附上位址:
http://open.yundasys.com/index.php?g=&m=ApiTools&a=exm還有接口的一些SDK檔案位址,這個就各位觀衆大老爺們自己去看了:
http://open.yundasys.com/index.php?g=&m=ApiTools&a=apps&id=14解決方案
上代碼走起:基礎參數的模型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
//請求參數
class RequestVO
{
/// <summary>
/// XML資料内容
/// </summary>
public string xmldata { get; set; }
/// <summary>
/// 合作社群ID,由韻達給大客戶提供
/// </summary>
public string partnerid { get; set; }
/// <summary>
/// 密碼
/// </summary>
public string password { get; set; }
/// <summary>
/// 資料請求類型,如request=data;其中data表示下單,詳細請見request字典表
/// </summary>
public string request { get; set; }
/// <summary>
/// 請求的版本,目前版本為1.0
/// </summary>
public string version { get; set; }
}
}
主體參數模型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace ConsoleApplication2
{
/// <summary>
/// 資料體
/// </summary>
public class Orders
{
[XmlElement("order")]
public List<Order> order { get; set; }
}
/// <summary>
/// 韻達取号訂單資訊
/// </summary>
public class Order
{
/// <summary>
/// 訂單唯一序列号
/// </summary>
public string order_serial_no { get; set; }
/// <summary>
/// 大客戶系統訂單的訂單号
/// </summary>
public string khddh { get; set; }
/// <summary>
/// 内部參考号,供大客戶自己使用,可以是客戶的客戶編号
/// </summary>
public string nbckh { get; set; }
/// <summary>
/// 單号
/// </summary>
public string mailno { get; set; }
/// <summary>
/// 發件人
/// </summary>
[XmlElement("sender")]
public Sender sender { get; set; }
/// <summary>
/// 收件人
/// </summary>
[XmlElement("receiver")]
public Receiver receiver { get; set; }
/// <summary>
/// 物品重量
/// </summary>
public long weight { get; set; }
/// <summary>
/// 尺寸,格式(長,寬,高),機關cm
/// </summary>
public string size { get; set; }
/// <summary>
/// 貨物金額
/// </summary>
public decimal value { get; set; }
/// <summary>
/// 商品集合
/// </summary>
[XmlElement("items")]
public Items items { get; set; }
/// <summary>
/// 訂單備注
/// </summary>
public string remark { get; set; }
/// <summary>
/// 可以自定義顯示資訊1
/// </summary>
public string cus_area1 { get; set; }
/// <summary>
/// 可以自定義顯示資訊2
/// </summary>
public string cus_area2 { get; set; }
}
public class Sender
{
/// <summary>
/// 姓名
/// </summary>
public string name { get; set; }
/// <summary>
/// 公司
/// </summary>
public string company { get; set; }
/// <summary>
/// 嚴格按照國家行政區劃,省市區三級,逗号分隔。示例上海市,上海市,青浦區(cod訂單必填)
/// </summary>
public string city { get; set; }
/// <summary>
/// 需要将省市區劃資訊加上,例如:上海市,上海市,青浦區盈港東路7766号
/// </summary>
public string address { get; set; }
/// <summary>
/// 郵編
/// </summary>
public string postcode { get; set; }
/// <summary>
/// 固定電話
/// </summary>
public string phone { get; set; }
/// <summary>
/// 行動電話固定電話或行動電話至少填一項
/// </summary>
public string mobile { get; set; }
public string branch { get; set; }
}
public class Receiver
{
/// <summary>
/// 姓名
/// </summary>
public string name { get; set; }
/// <summary>
/// 公司
/// </summary>
public string company { get; set; }
/// <summary>
/// 嚴格按照國家行政區劃,省市區三級,逗号分隔。示例上海市,上海市,青浦區(cod訂單必填)
/// </summary>
public string city { get; set; }
/// <summary>
/// 需要将省市區劃資訊加上,例如:上海市,上海市,青浦區盈港東路7766号
/// </summary>
public string address { get; set; }
/// <summary>
/// 郵編
/// </summary>
public string postcode { get; set; }
/// <summary>
/// 固定電話
/// </summary>
public string phone { get; set; }
/// <summary>
/// 行動電話固定電話或行動電話至少填一項
/// </summary>
public string mobile { get; set; }
public string branch { get; set; }
}
/// <summary>
/// 明細集合
/// </summary>
public class Items
{
[XmlElement("item")]
public List<Item> item { get; set; }
}
/// <summary>
/// 明細資訊
/// </summary>
public class Item
{
/// <summary>
/// 商品名稱
/// </summary>
public string name { get; set; }
/// <summary>
/// 商品數量
/// </summary>
public int number { get; set; }
/// <summary>
/// 商品備注
/// </summary>
public string remark { get; set; }
}
}
請求方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Collections.Specialized;
using System.Net;
namespace ConsoleApplication1
{
/// <summary>
/// POST送出
/// </summary>
class HttpClient
{
/// <summary>
///
/// </summary>
/// <param name="url"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static HttpWebResponse post(String url, IDictionary<string, string> parameters)
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
//如果需要POST資料
if (!(parameters == null || parameters.Count == 0))
{
StringBuilder buffer = new StringBuilder();
int i = 0;
foreach (string key in parameters.Keys)
{
if (i > 0)
{
buffer.AppendFormat("&{0}={1}", key, parameters[key]);
}
else
{
buffer.AppendFormat("{0}={1}", key, parameters[key]);
}
i++;
}
byte[] data = Encoding.UTF8.GetBytes(buffer.ToString());
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
}
return request.GetResponse() as HttpWebResponse;
}
/// <summary>
///
/// </summary>
/// <param name="url"></param>
/// <param name="data"></param>
/// <returns></returns>
public static String post(String url, String postdata)
{
try {
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] data = Encoding.UTF8.GetBytes(postdata.ToString());
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string outMessage = sr.ReadToEnd();
sr.Close();
return outMessage;
} catch (Exception ex) {
throw ex;
}
}
}
}
要求
目前按照SDK的要求:
請求封包說明:
1. 資料傳輸以HTTP POST方式發送,資料字元集一律采用UTF-8
2. xmldata首先需要進行base64編碼
3. validation的效驗方式采用 MD5(xmldata + partnerid + 密碼),這裡的加号為字元串連接配接符号。
4. 所有參數最終均須在完成資料轉換後進行URL編碼。
請求封包詳細解釋:
1.假設partnerid為YUNDA;密碼為123456;xmldata内容為
<order></order>
2.xmldata經過base64編碼以後變成PG9yZGVyPjwvb3JkZXI+
3.那麼要簽名的内容為PG9yZGVyPjwvb3JkZXI+YUNDA123456,經過md5後的内容就為f197e870a12528e38cb483b4e371f4ea
4.然後再對xmldata經過URL編碼,得到字元串PG9yZGVyPjwvb3JkZXI%2B
5.同樣需要對其他字段進行URL編碼,否則可能會影響POST傳遞,具體請參見HTTP POST傳輸協定
6.最終要發送的資料為: partnerid=YUNDA&version=1.0&request=data&xmldata=PG9yZGVyPjwvb3JkZXI%2B&validation=f197e870a12528e38cb483b4e371f4ea
不拉不拉不拉,一大堆,大老爺們自己去看,這些資料轉換的方法我直接貼出:
using System;
using System.Text;
using System.Web;
using System.IO;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class DataTransform
{
/// <summary>
/// 組裝主體内容
/// </summary>
/// <param name="requestVO"></param>
/// <returns></returns>
public static String signData(RequestVO requestVO)
{
String xmldata = Convert.ToBase64String(System.Text.Encoding.GetEncoding("UTF-8").GetBytes(requestVO.xmldata));
string validation = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(xmldata + requestVO.partnerid + requestVO.password, "MD5").ToLower();
string signdata = "partnerid=" + requestVO.partnerid + "&version=" + requestVO.version + "&request=" + requestVO.request + "&xmldata=" + HttpUtility.UrlEncode(xmldata) + "&validation=" + validation;
return signdata;
}
/// <summary>
/// 内容資料轉換XML
/// </summary>
/// <param name="type"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static String obj2Xml(Type type, Object obj)
{
XmlSerializer xml = new XmlSerializer(type);
String xmldata = "";
using (MemoryStream stream = new MemoryStream())
{
try
{
xml.Serialize(stream, obj);
xmldata = Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int)stream.Length);
}
catch (Exception)
{
throw;
}
}
return xmldata;
}
/// <summary>
/// 内容清洗轉換
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
public static string xmlformat(string xml) {
try {
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(xml);
System.IO.StringWriter sw = new System.IO.StringWriter();
using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(sw))
{
writer.Indentation = 2; // the Indentation
writer.Formatting = System.Xml.Formatting.Indented;
doc.WriteContentTo(writer);
writer.Close();
}
return sw.ToString();
} catch (Exception ex) {
return xml;
}
}
}
}
哈哈看了這麼多了 咱還沒看到請求電子面單的方法是吧 别急
這個類是我自己整合的在項目裡的,大老爺們先看看有不足之處 指點指點,應該能看明白!哈哈!案例的是winfrom,這個類沒有用上,方法我就不貼出來了,大佬自己去最底下載下傳吧!!!
using Commons.BLL;
using Commons.Model;
using Commons.Settings;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
namespace Commons.Helpers
{
public class YunDaApiHelper
{
SettingService _settingService=new SettingService();
/// <summary>
/// 韻達電子面單請求url
/// </summary>
private static string _createYunDaUrl;
/// <summary>
/// 取消韻達電子面單url
/// </summary>
private static string _colseYunDaUrl;
//韻達ID,密碼
private static string _partnerid;
private static string _password;
//發件人資訊
public static string FHCompany;
public static string FHName;
public static string FHMobile;
public static string FHProvinceName;
public static string FHCityName;
public static string FHExpAreaName;
public static string FHAddress;
public YunDaApiHelper()
{//_createYunDaUrl = "http://orderdev.yundasys.com:10110/cus_order/order_interface/interface_receive_order__mailno.php";//測試
//_colseYunDaUrl = "http://orderdev.yundasys.com:10110/cus_order/order_interface/interface_cancel_order.php";//測試
var settings = _settingService.LoadSetting<KdniaoSettings>();
_createYunDaUrl = settings.CreateYunDaUrl;
_colseYunDaUrl = settings.ColseYunDaUrl;
FHCompany = settings.FHCompany;
FHName = settings.FHName;
FHMobile = settings.FHMobile;
FHProvinceName = settings.FHProvinceName;
FHCityName = settings.FHCityName;
FHExpAreaName = settings.FHExpAreaName;
FHAddress = settings.FHAddress;
_partnerid = settings.YdPartnerId;
_password = settings.YdPassword;
}
/// <summary>
/// 申請韻達電子面單
/// </summary>
/// <param name="order"></param>
/// <returns></returns>
public YunDaResult CreateYunDaNo(Order order)
{
var model = new YDOrderModel();
var send = new YDSender
{
name = FHName,//發貨人名稱
company = FHCompany,//發貨人公司
mobile = FHMobile,//發貨人行動電話或手機
address = FHAddress,//發貨人位址,需要将省市區劃資訊加上,例如:上海市,上海市,青浦區盈港東路7766号
postcode = "510000", //郵編
city = FHProvinceName + FHCityName + FHExpAreaName,//嚴格按照國家行政區劃,省市區三級,逗号分隔。示例上海市,上海市,青浦區(cod訂單必填)
phone = "",//固話
branch = ""
};
order.sender = send;
model.order = order;
try
{
var xml = Obj2Xml(typeof (YDOrderModel), model);
var requestVo = new YunDaRequestModel
{
xmldata = xml,
partnerid = _partnerid,
password = _password,
version = "1.0",
request = "data"
};
var data = SignData(requestVo);
var result = Post(_createYunDaUrl, data);
var msgBody = new XmlDocument();
msgBody.LoadXml(result);
var status = GetXmlValue(msgBody, "status");
var dto = new YunDaResult
{
status = Convert.ToInt32(status),
order_serial_no = GetXmlValue(msgBody, "order_serial_no"),
msg = GetXmlValue(msgBody, "msg"),
mail_no = GetXmlValue(msgBody, "mail_no")
};
return dto;
}
catch (Exception ex)
{
var dto = new YunDaResult
{
status = (int) CustomBoolean.False,
msg = ex.ToString()
};
return dto;
}
}
/// <summary>
/// 取消韻達電子面單
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
public YunDaResult ColseYunDaNo(string xml)
{
var requestVo = new YunDaRequestModel
{
xmldata = Xmlformat(xml),
partnerid = _partnerid,
password = _password,
version = "1.0",
request = "cancel_order"
};
try
{
var data = SignData(requestVo);
var result = Post(_colseYunDaUrl, data);
var msgBody = new XmlDocument();
msgBody.LoadXml(result);
var dto = new YunDaResult
{
status = Convert.ToInt32(GetXmlValue(msgBody, "status")),
order_serial_no = GetXmlValue(msgBody, "order_serial_no"),
msg = GetXmlValue(msgBody, "msg")
};
return dto;
}
catch (Exception ex)
{
var dto = new YunDaResult
{
status = (int) CustomBoolean.False,
msg = ex.ToString()
};
return dto;
}
}
#region 組裝資料以及轉化xml資料
/// <summary>
/// 組裝主體内容
/// </summary>
/// <param name="requestVo"></param>
/// <returns></returns>
public static string SignData(YunDaRequestModel requestVo)
{
var xmldata = Convert.ToBase64String(System.Text.Encoding.GetEncoding("UTF-8").GetBytes(requestVo.xmldata));
var validation = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(xmldata + requestVo.partnerid + requestVo.password, "MD5").ToLower();
var signdata = "partnerid=" + requestVo.partnerid + "&version=" + requestVo.version + "&request=" + requestVo.request + "&xmldata=" + HttpUtility.UrlEncode(xmldata) + "&validation=" + validation;
return signdata;
}
/// <summary>
/// 内容資料轉換XML
/// </summary>
/// <param name="type"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static string Obj2Xml(Type type, object obj)
{
var xml = new XmlSerializer(type);
var xmldata = "";
using (var stream = new MemoryStream())
{
try
{
xml.Serialize(stream, obj);
xmldata = Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int)stream.Length);
}
catch (Exception)
{
throw;
}
}
return xmldata;
}
/// <summary>
/// 内容清洗轉換
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
public static string Xmlformat(string xml)
{
try
{
var doc = new System.Xml.XmlDocument();
doc.LoadXml(xml);
var sw = new System.IO.StringWriter();
using (var writer = new System.Xml.XmlTextWriter(sw))
{
writer.Indentation = 2; // the Indentation
writer.Formatting = System.Xml.Formatting.Indented;
doc.WriteContentTo(writer);
writer.Close();
}
return sw.ToString();
}
catch (Exception ex)
{
return xml;
}
}
#endregion
#region Post資料請求
public static HttpWebResponse Post(string url, IDictionary<string, string> parameters)
{
var request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
//如果需要POST資料
if (!(parameters == null || parameters.Count == 0))
{
var buffer = new StringBuilder();
var i = 0;
foreach (var key in parameters.Keys)
{
buffer.AppendFormat(i > 0 ? "&{0}={1}" : "{0}={1}", key, parameters[key]);
i++;
}
var data = Encoding.UTF8.GetBytes(buffer.ToString());
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
}
return request.GetResponse() as HttpWebResponse;
}
public static string Post(string url, string postdata)
{
try
{
var request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
var data = Encoding.UTF8.GetBytes(postdata.ToString());
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = request.GetResponse() as HttpWebResponse;
var sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
var outMessage = sr.ReadToEnd();
sr.Close();
return outMessage;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
#region MyRegion
/// <summary>
/// XML讀取對應的值
/// </summary>
/// <param name="msgBody">xml</param>
/// <param name="nodeName">節點名稱</param>
/// <returns>傳回節點值</returns>
public static string GetXmlValue(XmlDocument msgBody, string nodeName)
{
var fromUserName = msgBody.GetElementsByTagName(nodeName).Item(0);
return fromUserName?.InnerText;
}
#endregion
}
}
SettingService 這個是系統配置參數,應該沒毛病哈哈!
so,下邊咱來看看案例的界面
注
賬号:韻達的客戶号
密碼:是韻達二維碼VIP用戶端的《接口聯調密碼》
結語
案例很簡單,但是有包含蠻多東東的,各位大佬隻要是搞通一個,那估摸着就都沒問題了!
連結:https://pan.baidu.com/s/1T3X8-TLorn5R8nZfpKkqOg 密碼:m645 ------位址要是挂了,各位直接聯系我哈!
好了!各位大老爺覺着這篇文章要是不錯就點個贊咯