old_flsystem/类库/Api.Framework/Cps/JingdongApi.cs

407 lines
16 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// 京东操作Api
/// </summary>
public class JingdongApi : BaseCpsApi
{
#region
/// <summary>
/// 构造方法
/// </summary>
/// <param name="member">fl_cps_member实例</param>
public JingdongApi(fl_cps_member member) : base(member) { }
/// <summary>
/// 刷新授权
/// </summary>
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<string> WhiteApiList = new List<string>() {
"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;
}
/// <summary>
/// 发送京东报文
/// </summary>
/// <param name="api">api接口</param>
/// <param name="data">参数</param>
/// <returns></returns>
public Dictionary<string, object> 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<string, string> param = new Dictionary<string, string>();
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<string, object> 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<string, object>();
if (dic == null)
{
EventClient.OnEvent(this, $"【京东】 => 请求失败转换异常:{html}");
return new Dictionary<string, object>();
}
var response = api.Replace(".", "_") + "_response";
if (dic.ContainsKey(response))
{
var result = dic[response] as Dictionary<string, object>;
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<string, object>;
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<string, object>;
//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<string, object>();
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
#region 2021125
/// <summary>
/// 京东下载订单
/// </summary>
/// <param name="start_time">开始时间</param>
/// <param name="end_time">结束时间</param>
/// <param name="page_index">第几页</param>
/// <param name="page_size">每页数量,上限500</param>
/// <param name="type">订单类型</param>
/// <returns></returns>
internal Dictionary<string, object> 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<string, string> parameters, string appSecret)
{
StringBuilder sb = new StringBuilder(appSecret);
//按照规则拼成字符串
foreach (KeyValuePair<string, string> 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
}
}