329 lines
13 KiB
C#
329 lines
13 KiB
C#
|
using Api.Framework.Model;
|
|||
|
using Api.Framework.Tools;
|
|||
|
using Api.Framework.Utils;
|
|||
|
using CsharpHttpHelper;
|
|||
|
using Newtonsoft.Json;
|
|||
|
using Newtonsoft.Json.Linq;
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Net;
|
|||
|
using System.Security.Cryptography;
|
|||
|
using System.Text;
|
|||
|
using System.Text.RegularExpressions;
|
|||
|
using System.Threading;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using Api.Framework.EntityTmp.WeiPinHui;
|
|||
|
|
|||
|
namespace Api.Framework.Cps
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 唯品会操作Api
|
|||
|
/// </summary>
|
|||
|
public class WeipinhuiApi : BaseCpsApi
|
|||
|
{
|
|||
|
#region 固定函数
|
|||
|
/// <summary>
|
|||
|
/// 构造方法
|
|||
|
/// </summary>
|
|||
|
/// <param name="member"></param>
|
|||
|
internal WeipinhuiApi(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}");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//private string AppKey = "0c85e6c0";
|
|||
|
//private string AppSecret = "F921D8D3EFEAEA5B0387158512AEF909";
|
|||
|
|
|||
|
#region
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 发送唯品会报文
|
|||
|
/// </summary>
|
|||
|
/// <param name="api">api接口</param>
|
|||
|
/// <param name="data">参数</param>
|
|||
|
/// <returns></returns>
|
|||
|
public T SendWeipinhui<T>(string api, object data)
|
|||
|
{
|
|||
|
if (!Member.is_valid) return default(T);
|
|||
|
|
|||
|
var isRefToken = false;
|
|||
|
|
|||
|
var html = string.Empty;
|
|||
|
for (int i = 0; i < 3; i++)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var query = GetRequestData(api, data);
|
|||
|
var postData = JsonConvert.SerializeObject(data);
|
|||
|
var http = new HttpHelper();
|
|||
|
var httpItem = new HttpItem()
|
|||
|
{
|
|||
|
URL = $"https://vop.vipapis.com/?{query}",
|
|||
|
Method = "POST",
|
|||
|
Timeout = 5000,
|
|||
|
ReadWriteTimeout = 5000,
|
|||
|
Accept = "text/html, application/xhtml+xml, */*",
|
|||
|
ContentType = "application/json;",
|
|||
|
Postdata = postData,
|
|||
|
};
|
|||
|
|
|||
|
var result = http.GetHtml(httpItem);
|
|||
|
|
|||
|
if (result.StatusCode == HttpStatusCode.OK)
|
|||
|
{
|
|||
|
html = result.Html;
|
|||
|
if (!string.IsNullOrWhiteSpace(html))
|
|||
|
{
|
|||
|
var jObj = JObject.Parse(html);
|
|||
|
var resultCode = jObj["returnCode"]?.ToString();
|
|||
|
if (resultCode == "0")
|
|||
|
{
|
|||
|
T t = JsonConvert.DeserializeObject<T>(html);
|
|||
|
return t;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//请求太快了
|
|||
|
if (resultCode == "1008")
|
|||
|
{
|
|||
|
Thread.Sleep(5000);
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
throw new Exception(html);
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
LogHelper.GetSingleObj().Error("", $@"唯品会请求异常A.,{Member.usernick}({Member.username}),登录时间:{Member.logintime.ToString("yyyy-MM-dd HH:mm:ss")}
|
|||
|
{api}
|
|||
|
{html}
|
|||
|
{ex.Message} - {ex.StackTrace}");
|
|||
|
|
|||
|
//token失效的错误数据
|
|||
|
//{"returnCode":"vipapis.oauth-invalidate-failure","returnMessage":"oauth-error-code[30111]description[access token invalid]"}
|
|||
|
|
|||
|
if (ex.Message.Contains("invalid") || html.Contains("invalid") || html.Contains("token") || html.ToLower().Contains("does not exist"))
|
|||
|
{
|
|||
|
//没有刷新过token
|
|||
|
if (isRefToken == false)
|
|||
|
{
|
|||
|
isRefToken = true;
|
|||
|
if (RefToken())
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
EventClient.OnEvent(this, $@"【唯品会】 => 请求异常1:{this.Member.usernick}({this.Member.username}),注:请重新登录唯品会!!!");
|
|||
|
Member.is_valid = false;
|
|||
|
return default(T);
|
|||
|
}
|
|||
|
Thread.Sleep(500);
|
|||
|
}
|
|||
|
}
|
|||
|
return default(T);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 唯品会下载订单
|
|||
|
/// </summary>
|
|||
|
/// <param name="_startTime">开始时间</param>
|
|||
|
/// <param name="_endTime">结束时间</param>
|
|||
|
/// <param name="page_index">第几页</param>
|
|||
|
/// <param name="page_size">每页数量</param>
|
|||
|
/// <returns></returns>
|
|||
|
internal OrderResponseResult DownOrder(DateTime _startTime, DateTime _endTime, int page_index, int page_size)
|
|||
|
{
|
|||
|
if (!Member.is_valid)
|
|||
|
{
|
|||
|
//Api.Framework.Utils.LogHelper.GetSingleObj().Error("唯品会订单下载异常.过期?", $"需要重新登录,{this.Member.usernick}({this.Member.username})");
|
|||
|
throw new Exception("vipapis.oauth-invalidate-failure");
|
|||
|
}
|
|||
|
|
|||
|
var startTime = Util.GetTimeSpan(_startTime, true); //每小时同步订单
|
|||
|
var endTime = Util.GetTimeSpan(_endTime, true); //每小时同步订单
|
|||
|
//time = "2019042216";
|
|||
|
//TODO 订单下载接口
|
|||
|
var result = this.SendWeipinhui<OrderResponseResult>("com.vip.adp.api.open.service.UnionOrderService-1.0.0#orderListWithOauth", new
|
|||
|
{
|
|||
|
queryModel = new
|
|||
|
{
|
|||
|
//status = key,//订单状态:0-不合格,1-待定,2-已完结,该参数不设置默认代表全部状态
|
|||
|
//orderTimeStart = page_index,//订单时间起始 时间戳 单位毫秒
|
|||
|
//orderTimeEnd = page_size,//订单时间结束 时间戳 单位毫秒
|
|||
|
page = page_index,//页码:从1开始
|
|||
|
pageSize = page_size,//页面大小:默认20
|
|||
|
requestId = Util.GetUUID(),//请求id:调用方自行定义,用于追踪请求,单次请求唯一,建议使用UUID
|
|||
|
updateTimeStart = startTime,//更新时间-起始 时间戳 单位毫秒
|
|||
|
updateTimeEnd = endTime,//更新时间-结束 时间戳 单位毫秒
|
|||
|
//orderSnList = ,//订单号列表:当传入订单号列表时,订单时间和更新时间区间可不传入
|
|||
|
//vendorCode = ,//vendorCode,工具商方式下会传入
|
|||
|
//chanTag = ,//渠道标识,即推广位PID
|
|||
|
}
|
|||
|
});
|
|||
|
//if (_rst == null || _rst.result == null || _rst.returnCode == null || _rst.returnCode != "0")
|
|||
|
// throw new Exception(JsonConvert.SerializeObject(_rst));
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Sign计算
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 计算签名,返回请求阿里妈妈服务器的参数
|
|||
|
/// </summary>
|
|||
|
/// <param name="api">api</param>
|
|||
|
/// <param name="data">参数</param>
|
|||
|
/// <returns></returns>
|
|||
|
private string GetRequestData(string api, object data)
|
|||
|
{
|
|||
|
//try
|
|||
|
//{
|
|||
|
var reg = Regex.Match(api, "(?<service>.+?)-(?<version>.+?)#(?<method>.+)");
|
|||
|
if (!reg.Success) throw new Exception($"无法识别“{api}”API请求!");
|
|||
|
|
|||
|
var param = new Dictionary<string, string>();
|
|||
|
if (Token == null)
|
|||
|
{
|
|||
|
throw new Exception("invalid ..");
|
|||
|
}
|
|||
|
|
|||
|
param["accessToken"] = Token.access_token;
|
|||
|
param["appKey"] = "9f7a9b3d";//Token.appid;
|
|||
|
param["format"] = "JSON";
|
|||
|
param["language"] = "zh";
|
|||
|
param["method"] = reg.Groups["method"].Value;
|
|||
|
param["service"] = reg.Groups["service"].Value;
|
|||
|
param["version"] = reg.Groups["version"].Value;
|
|||
|
param["timestamp"] = Util.GetTimeSpan(DateTime.Now, false).ToString();
|
|||
|
|
|||
|
//计算签名
|
|||
|
string sign = GetSign(param, "074B0E1FFB94334FDEC993913884EC7F"/*Token.appkey*/, data);
|
|||
|
param["sign"] = sign;
|
|||
|
|
|||
|
return HttpExtend.BuildQuery(param);
|
|||
|
//}
|
|||
|
//catch (Exception ex)
|
|||
|
//{
|
|||
|
|
|||
|
//}
|
|||
|
return string.Empty;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 计算sign
|
|||
|
/// </summary>
|
|||
|
/// <param name="parameters">计算的参数</param>
|
|||
|
/// <param name="secret">appkey</param>
|
|||
|
/// <param name="bizParam">请求的参数</param>
|
|||
|
/// <returns></returns>
|
|||
|
private string GetSign(Dictionary<string, string> parameters, string secret, object bizParam = null)
|
|||
|
{
|
|||
|
// 第一步:把字典按Key的字母顺序排序
|
|||
|
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal);
|
|||
|
|
|||
|
//// 第二步:把所有参数名和参数值串在一起
|
|||
|
StringBuilder query = new StringBuilder();
|
|||
|
foreach (KeyValuePair<string, string> kv in sortedParams)
|
|||
|
{
|
|||
|
if (!string.IsNullOrEmpty(kv.Key) && !string.IsNullOrEmpty(kv.Value))
|
|||
|
query.Append(kv.Key).Append(kv.Value);
|
|||
|
}
|
|||
|
|
|||
|
// 第三步:把请求主体拼接在参数后面
|
|||
|
var boby = string.Empty;
|
|||
|
if (bizParam != null)
|
|||
|
boby = JsonConvert.SerializeObject(bizParam);
|
|||
|
if (!string.IsNullOrEmpty(boby))
|
|||
|
{
|
|||
|
query.Append(boby);
|
|||
|
}
|
|||
|
|
|||
|
var sss = query.ToString();
|
|||
|
// 第四步: 使用HMAC加密
|
|||
|
HMACMD5 hmac = new HMACMD5(Encoding.UTF8.GetBytes(secret));
|
|||
|
var bytes = hmac.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
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取唯品会推广位
|
|||
|
/// </summary>
|
|||
|
/// <param name="api">WeipinhuiApi对象</param>
|
|||
|
/// <param name="page">第几页</param>
|
|||
|
/// <param name="pageSize">每页的数量</param>
|
|||
|
/// <returns></returns>
|
|||
|
public static QueryPid GetWphTgw(WeipinhuiApi api, int page = 1, int pageSize = 20)
|
|||
|
{
|
|||
|
var res = api.SendWeipinhui<QueryPids>("com.vip.adp.api.open.service.UnionPidService-1.0.0#queryPidWithOauth", new { pidQueryRequest = new { requestId = Util.GetUUID(), page = page, pageSize = pageSize } });
|
|||
|
if (res != null && res.returnCode == "0")
|
|||
|
{
|
|||
|
return res.result;
|
|||
|
}
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
///// <summary>
|
|||
|
///// 获取唯品会推广位
|
|||
|
///// </summary>
|
|||
|
///// <param name="api">WeipinhuiApi对象</param>
|
|||
|
///// <param name="page">第几页</param>
|
|||
|
///// <param name="pageSize">每页的数量</param>
|
|||
|
///// <returns></returns>
|
|||
|
//public static ArrayList GetWphTgw(WeipinhuiApi api, out int total, int page = 1, int pageSize = 20)
|
|||
|
//{
|
|||
|
// total = 0;
|
|||
|
// var res = api.SendWeipinhui("com.vip.adp.api.open.service.UnionPidService-1.0.0#queryPidWithOauth", new { pidQueryRequest = new { requestId = Util.GetUUID(), page = page, pageSize = pageSize } });
|
|||
|
// if (res.ContainsKey("returnCode") && res["returnCode"].ToString() == "0")
|
|||
|
// {
|
|||
|
// res = res["result"] as Dictionary<string, object>;
|
|||
|
// total = int.Parse(res["total"].ToString());
|
|||
|
// return res["pidInfoList"] as ArrayList;
|
|||
|
// }
|
|||
|
// return null;
|
|||
|
//}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 创建推广位
|
|||
|
/// </summary>
|
|||
|
/// <param name="api">WeipinhuiApi对象</param>
|
|||
|
/// <param name="pidList">要创建的推广位名称</param>
|
|||
|
public static void CreateWphTgw(WeipinhuiApi api, List<string> pidList = null)
|
|||
|
{
|
|||
|
if (pidList == null)
|
|||
|
pidList = new List<string>() { "WphDefault" };
|
|||
|
api.SendWeipinhui<object>("com.vip.adp.api.open.service.UnionPidService-1.0.0#genPidWithOauth", new { pidGenRequest = new { requestId = Util.GetUUID(), pidNameList = pidList } });
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|