using Api.Framework.Model; using CsharpHttpHelper; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading; namespace Api.Framework.Cps { /// /// 拼多多操作Api /// public class PinduoduoApi : BaseCpsApi { #region 静态 /// /// 拼多多接口请求地址 /// private const string app_host = "http://gw-api.pinduoduo.com/api/router"; /// /// 计算sign /// /// 参数 /// appkey /// private string SignTopRequest(Dictionary parameters, string appkey) { // 第一步:把字典按Key的字母顺序排序 IDictionary sortedParams = new SortedDictionary(parameters, StringComparer.Ordinal); // 第二步:把所有参数名和参数值串在一起 StringBuilder query = new StringBuilder(); query.Append(appkey); foreach (KeyValuePair kv in sortedParams) { if (!string.IsNullOrEmpty(kv.Key) && !string.IsNullOrEmpty(kv.Value)) { query.Append(kv.Key).Append(kv.Value); } } // 第四步 byte[] bytes; query.Append(appkey); MD5 md5 = MD5.Create(); bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query.ToString())); // 第五步:把二进制转化为大写的十六进制 StringBuilder result = new StringBuilder(); for (int i = 0; i < bytes.Length; i++) { result.Append(bytes[i].ToString("X2")); } return result.ToString(); } #endregion #region 实际操作 /// /// 构造方法 /// /// internal PinduoduoApi(fl_cps_member member) : base(member) { } /// /// 刷新授权 /// internal void RefreshStatus() { for (int i = 0; i < 3; i++) { try { //if (Member.cpstype == Enums.CpsType.多多进宝) // Console.WriteLine(); //UpdateCookies(); var result = SendServer("refresh_token", new { username = Member.username }); if (!result.ok) throw new Exception(result.message.ToString()); Member.online = true; RefToken(); break; } catch (Exception ex) { if (i < 2) { Thread.Sleep(10000); continue; } else EventClient.OnEvent(this, $"ERROR:{this.GetType()}@{System.Reflection.MethodBase.GetCurrentMethod().Name}->{ex.Message}"); } } } /// /// 发送拼多多报文 /// /// 请求的api /// 参数 /// public Dictionary SendPinduoduo(string api, object data) { int number = 0; string html = string.Empty; Next: try { number++; //throw new Exception("{\"error_msg\":\"公共参数错误: access_token\",\"sub_msg\":\"公共参数错误: access_token\",\"sub_code\":\"10019\",\"error_code\":10019,\"request_id\":\"16249438515389810\"}"); Dictionary param = new Dictionary(); var type = data.GetType().GetProperties(); foreach (var item in type) { var _value = item.GetValue(data).ToString(); param[item.Name] = _value; } //if (api != "pdd.ddk.oauth.order.list.increment.get" && api != "pdd.ddk.oauth.goods.search") if (api.Contains("oauth")) param["access_token"] = Token.access_token; param["type"] = api; param["client_id"] = Token.appid; //param["timestamp"] = ((DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000).ToString();//HttpExtend.GetTimeStamp(DateTime.Now).ToString(); param["timestamp"] = HttpExtend.GetTimeStamp(); param["data_type"] = "JSON"; var sign = SignTopRequest(param, Token.appkey); param["sign"] = sign; HttpHelper http = new HttpHelper(); HttpItem _item = new HttpItem() { URL = app_host, Method = "Post",//URL 可选项 默认为Get Timeout = 10000,//连接超时时间 可选项默认为100000 ReadWriteTimeout = 10000,//写入Post数据超时时间 可选项默认为30000 IsToLower = false,//得到的HTML代码是否转成小写 可选项默认转小写 Cookie = "",//字符串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 = "",//来源URL 可选项 Postdata = HttpExtend.BuildQuery(param),//Post数据 可选项GET时不需要写 }; html = http.GetHtml(_item).Html; //if (html.Contains("access_token已过期")) Member.online = false; //else if (api == "pdd.ddk.oauth.order.list.increment.get") Member.online = true; var dic = HttpExtend.JsonToDictionary(html); if (dic.ContainsKey("error_response")) { //EventClient.OnEvent(this, $"拼多多接口异常:{this.Member.username}({this.Member.usernick})->{api}->{html}"); throw new Exception(HttpHelper.ObjectToJson(dic["error_response"])); } return dic; } catch (Exception ex) { if (ex.Message.Contains("access_token") && ((ex.Message.Contains("10019") || ex.Message.Contains("20033") || ex.Message.Contains("20032")))) { Thread.Sleep(1000); if (this.Member != null && RefToken() && this.Member.is_valid && number < 3) goto Next; else { //Member.online = false; //ApiClient.GetSession().SaveOrUpdate(Member); Member.is_valid = false; if (CpsClient.GuideMembers.FirstOrDefault(f => f.username == Member.username) == null) { ApiClient.GetSession().SaveOrUpdate(Member); } EventClient.OnEvent(this, $@"拼多多异常:{this.Member.username}({this.Member.usernick}),{ex.Message} - {ex.StackTrace} ,注:请重新登录拼多多,{api}"); throw new Exception($"{this.Member.username}({this.Member.usernick}),{ex.Message},注:请重新登录拼多多"); } } else if (html.Contains("超时")) { goto Next; } throw ex; } } /// /// 拼多多下载订单 /// /// 开始时间 /// 结束时间 /// 每页数量默认50安全 /// 第几页 /// internal Dictionary DownOrder(DateTime start_time, DateTime end_time, int page_index, int page_size) { if (!Member.is_valid) throw new Exception("需要重新登录"); var _rst = this.SendPinduoduo("pdd.ddk.oauth.order.list.increment.get", new { start_update_time = HttpExtend.GetTimeStamp(start_time), end_update_time = HttpExtend.GetTimeStamp(end_time), page_size = page_size, page = page_index }); if (_rst.ContainsKey("order_list_get_response")) { return _rst["order_list_get_response"] as Dictionary; } return null; } #endregion } }