using Api.Framework.Model; using Api.Framework.Tools; using CsharpHttpHelper; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Api.Framework.Cps { /// /// 京东操作Api /// public class JingdongApi : BaseCpsApi { #region 固定函数 /// /// 构造方法 /// /// fl_cps_member实例 public JingdongApi(fl_cps_member member) : base(member) { } /// /// 刷新授权 /// public void RefreshStatus() { try { var result = SendServer("refresh_token", new { username = Member.username }); if (!result.ok) throw new Exception(result.message.ToString()); Member.online = true; } catch (Exception ex) { EventClient.OnEvent(this, $"ERROR:{this.GetType()}-{System.Reflection.MethodBase.GetCurrentMethod().Name}->{ex.Message}"); } } #region private static int AppKeysIndex = -1; private static string[] AppKeys = null; private static List WhiteApiList = new List() { "jd.union.open.promotion.byunionid.get"/*转链*/, "jd.union.open.position.query"/*推广位*/, "jd.union.open.position.create"/*创建推广位*/, "jd.union.open.goods.jingfen.query"/*京粉精选商品*/, "jd.union.open.goods.promotiongoodsinfo.query"/*根据skuid查询商品信息*/ }; private static string[] KeyInfo = null; private static DateTime UpdateKeyTime = DateTime.MinValue; private string[] GetKeySecret() { if (UpdateKeyTime.AddDays(1) < DateTime.Now) KeyInfo = null; if (KeyInfo == null) { for (int i = 0; i < 3; i++) { try { var data = this.SendServer("find_wangzhi", "webTool.asmx", new { name = "京东APPKEY" }).message.ToString(); if (!string.IsNullOrWhiteSpace(data)) { /* appkey="4363c9848d8a43c8b7b9e957d3adcbcf"; "474ae90f6930495988c28701b6be1d9a"; */ //data = "4363c9848d8a43c8b7b9e957d3adcbcf_474ae90f6930495988c28701b6be1d9a"; KeyInfo = data.Split(new string[] { "_" }, StringSplitOptions.RemoveEmptyEntries); break; } continue; } catch (Exception) { KeyInfo = null; Thread.Sleep(500); } } UpdateKeyTime = DateTime.Now; } return KeyInfo; } /// /// 发送京东报文 /// /// api接口 /// 参数 /// public Dictionary SendJingdong(string api, object data) { try { //执行次数 int num = 1; Next: string[] appKey = null; if (AppKeysIndex == -1) { //appkey = "4363c9848d8a43c8b7b9e957d3adcbcf"; //secretkey = "474ae90f6930495988c28701b6be1d9a"; if (WhiteApiList.Contains(api)) //appKey = new string[] { "dd09c846450c044cf4977357e25ef2cb", "8a610e949a0d4657b310def702728059" };//自己的目前30W appKey = GetKeySecret();//自己的目前30W if (appKey == null) appKey = new string[] { "4363c9848d8a43c8b7b9e957d3adcbcf", "474ae90f6930495988c28701b6be1d9a" };//别人的,无限制 } //else //{ // //第一次 // if (AppKeys == null || AppKeysIndex >= AppKeys.Length) // { // try // { // if (AppKeys != null && AppKeysIndex >= AppKeys.Length) AppKeysIndex = -1; // else if (AppKeys == null && AppKeysIndex != -1) AppKeysIndex = -1; // var result = base.SendServer("get_appkey", ""); // var msg = result.message.ToString(); // msg = ZipHelper.GZipDecompressString(msg); // AppKeys = msg.Split(','); // } // catch (Exception ex) // { // throw new Exception("获取京东授权KEY失败!" + ex.Message); // } // } // appKey = AppKeys[AppKeysIndex].Split('_'); //} Dictionary param = new Dictionary(); param["access_token"] = ""; param["app_key"] = appKey[0]; param["format"] = "json"; param["method"] = api; param["param_json"] = CsharpHttpHelper.HttpHelper.ObjectToJson(data);//param_json为空的时候需要写成 "{}" param["sign_method"] = "md5"; param["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); param["v"] = "1.0"; //计算签名 var sign = SignTopRequest(param, appKey[1]); param["sign"] = sign; if (param.ContainsKey("param_json")) { param["param_json"] = HttpHelper.URLEncode(param["param_json"]); } var _param = HttpHelper.URLDecode(HttpExtend.BuildQuery(param)); HttpHelper http = new HttpHelper(); HttpItem _item = new HttpItem() { URL = "https://router.jd.com/api?" + _param, Method = "get", Timeout = 10000, ReadWriteTimeout = 10000, IsToLower = false, Cookie = "", UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0", Accept = "text/html, application/xhtml+xml, */*", ContentType = "application/x-www-form-urlencoded", Referer = "" }; Dictionary dic = null; string html = string.Empty; for (int i = 0; i < 4; i++) { html = http.GetHtml(_item).Html; if (html.Contains("操作超时") || html.Contains("服务端异常")) { Thread.Sleep(200); continue; } else { dic = HttpExtend.JsonToDictionary(html); if (dic == null) continue; } break; } if (html.Contains("操作超时") || html.Contains("服务端异常")) return new Dictionary(); if (dic == null) { EventClient.OnEvent(this, $"【京东】 => 请求失败转换异常:{html}"); return new Dictionary(); } var response = api.Replace(".", "_") + "_response"; if (dic.ContainsKey(response)) { var result = dic[response] as Dictionary; if (result.ContainsKey("result")) { dic = HttpExtend.JsonToDictionary(result["result"].ToString()); } if (dic.ContainsKey("code")) { var code = dic["code"].ToString(); if (code != "200" && code != "1002016") { if (dic["message"].ToString().ToLower() == "授权key无权限或错误") { if (num < 3) { num++; goto Next; } //if (code == "1002006") throw new Exception("京东key失效"); throw new Exception(@"授权key无权限或错误"); } else { EventClient.OnEvent(this, $"京东接口异常:{this.Member.username}({this.Member.usernick})->{api}->{dic["message"]}"); throw new Exception(HttpHelper.ObjectToJson(dic["message"])); } } } return dic; } else if (dic.ContainsKey("errorResponse") || dic.ContainsKey("error_response"))//{"errorResponse":{"code":"3067","msg":"API GLOBAL LIMITER ACTIVE, REQUEST TIMES LIMITED"}} { if (dic.ContainsKey("errorResponse")) { var errorResponse = dic["errorResponse"] as Dictionary; if (errorResponse.ContainsKey("code") && (errorResponse["code"].ToString() == "3066" || errorResponse["code"].ToString() == "67")) { AppKeysIndex++; if (AppKeysIndex < AppKeys.Length) { goto Next; } else throw new Exception($".京东调用量饱和,暂时无法为您发起请求!"); } else { throw new Exception($".京东接口异常:({this.Member.usernick})->{api}->{HttpHelper.ObjectToJson(dic["errorResponse"])}"); } } else if (dic.ContainsKey("error_response")) { var errorResponse = dic["error_response"] as Dictionary; //if (errorResponse.ContainsKey("code") && errorResponse["code"] == "2") //{ if (errorResponse.ContainsKey("zh_desc") && errorResponse["zh_desc"].ToString().Contains("1天内访问接口")) { AppKeysIndex++; if (AppKeysIndex < AppKeys.Length) { goto Next; } else throw new Exception($".京东调用量饱和,暂时无法为您发起请求!"); } //} else { string code = string.Empty; if (errorResponse.ContainsKey("code")) code = errorResponse["code"].ToString(); throw new Exception($".京东接口异常:({this.Member.usernick})->{api}-> {code}.京东调用量饱和,暂时无法为您发起请求!"); } } } return new Dictionary(); } catch (Exception ex) { throw ex; } } #endregion #region 2021年1月25日 新接口 /// /// 京东下载订单 /// /// 开始时间 /// 结束时间 /// 第几页 /// 每页数量,上限500 /// 订单类型 /// internal Dictionary DownOrder(DateTime datetime, string key, int page_index, int page_size, int type = 3) { int i = 0; Next: try { var endTime = datetime.ToString("yyyy-MM-dd HH:mm:ss"); //每小时同步订单 var startTime = datetime.AddHours(-1).ToString("yyyy-MM-dd HH:mm:ss"); //每小时同步订单 var _rst = this.SendJingdong("jd.union.open.order.row.query", new { orderReq = new { key = key, pageIndex = page_index, pageSize = page_size, type = type, //订单时间查询类型(1:下单时间,2:完成时间(购买用户确认收货时间),3:更新时间 startTime = startTime, //查询时间,建议使用分钟级查询,格式: yyyyMMddHH, yyyyMMddHHmm或yyyyMMddHHmmss,如201811031212的查询范围从12:12:00-12:12:59 endTime = endTime, } }); return _rst; } catch (Exception ex) { if (i <= 3 && ex.Message == "未将对象引用设置到对象的实例。") //调用接口是偶尔会出现为将对象实例化的错误. { i++; Thread.Sleep(100); goto Next; } else throw ex; EventClient.OnEvent(this, $"更新京东订单异常: {ex.Message} - {ex.StackTrace}"); return null; } } #endregion #endregion #region Sign计算 private string SignTopRequest(Dictionary parameters, string appSecret) { StringBuilder sb = new StringBuilder(appSecret); //按照规则拼成字符串 foreach (KeyValuePair entry in parameters) { string name = entry.Key; string value = entry.Value; //检测参数是否为空 if (areNotEmpty(new string[] { name, value })) { sb.Append(name).Append(value); } } sb.Append(appSecret); //MD5 return md5(sb.ToString()); } private string md5(string source) { MD5 md5 = MD5.Create(); var result = md5.ComputeHash(Encoding.UTF8.GetBytes(source)); return byte2hex(result); } private string byte2hex(byte[] bytes) { //把二进制转化为大写的十六进制 StringBuilder result = new StringBuilder(); for (int i = 0; i < bytes.Length; i++) { result.Append(bytes[i].ToString("X2")); } return result.ToString(); } private bool areNotEmpty(string[] values) { bool result = true; if ((values == null) || (values.Length == 0)) result = false; else { foreach (var value in values) { result &= !isEmpty(value); } } return result; } private bool isEmpty(string value) { int strLen; if ((value == null) || ((strLen = value.Length) == 0)) return true; for (int i = 0; i < strLen; i++) { var ss = value[i]; if (!string.IsNullOrWhiteSpace(value[i].ToString())) { return false; } } return true; } #endregion } }