步步为盈
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
9.0 KiB

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Xml;
using Jd.Api.Parser;
using Jd.Api.Request;
using Jd.Api.Util;
using Newtonsoft.Json.Linq;
using System.Threading;
namespace Jd.Api
{
/// <summary>
/// 基于REST的Jd客户端。
/// </summary>
public class DefaultJdClient : IJdClient
{
public const string APP_KEY = "app_key";
public const string APP_PARAM = "360buy_param_json";
public const string FORMAT = "format";
public const string METHOD = "method";
public const string TIMESTAMP = "timestamp";
public const string VERSION = "v";
public const string SIGN = "sign";
public const string ACCESSTOKEN = "access_token";
public const string FORMAT_XML = "xml";
public const string FORMAT_JSON = "json";
public string serverUrl;
public string appKey;
public string appSecret;
public string accessToken;
private string Proxy;
private string format = FORMAT_JSON;
private bool isJava = false;
private WebUtils webUtils;
private IJdLogger topLogger;
private bool disableParser = false; // 禁用响应结果解释
private bool disableTrace = true; // 禁用日志调试功能
#region DefaultJdClient Constructors
public DefaultJdClient(string serverUrl, string appKey, string appSecret, bool isJava = false)
{
System.Net.ServicePointManager.DefaultConnectionLimit = 200;
this.appKey = appKey;
this.appSecret = appSecret;
this.serverUrl = serverUrl;
this.webUtils = new WebUtils();
this.topLogger = new DefaultJdLogger();
this.isJava = isJava;
}
public DefaultJdClient(string serverUrl, string appKey, string appSecret, string accessToken, string proxy)
: this(serverUrl, appKey, appSecret)
{
this.Proxy = proxy;
this.accessToken = accessToken;
}
public DefaultJdClient(string serverUrl, string appKey, string appSecret, string accessToken, bool isJava = false)
: this(serverUrl, appKey, appSecret, isJava)
{
this.accessToken = accessToken;
}
#endregion
public void SetTimeout(int timeout)
{
webUtils.Timeout = timeout;
}
public void SetDisableParser(bool disableParser)
{
this.disableParser = disableParser;
}
public void SetDisableTrace(bool disableTrace)
{
this.disableTrace = disableTrace;
}
public void SetJdLogger(IJdLogger topLogger)
{
this.topLogger = topLogger;
}
public void SetAccessToken(String accessToken)
{
this.accessToken = accessToken;
}
#region IJdClient Members
public T Execute<T>(IJdRequest<T> request) where T : JdResponse
{
return Execute<T>(request, accessToken);
}
public T Execute<T>(IJdRequest<T> request, string accessToken) where T : JdResponse
{
return Execute<T>(request, accessToken, DateTime.Now);
}
public T Execute<T>(IJdRequest<T> request, string accessToken, DateTime timestamp) where T : JdResponse
{
if (disableTrace)
{
return DoExecute<T>(request, accessToken, timestamp);
}
else
{
try
{
return DoExecute<T>(request, accessToken, timestamp);
}
catch (Exception e)
{
topLogger.Error(this.serverUrl + "\r\n" + e.StackTrace);
throw e;
}
}
}
#endregion
public string GetParamJson(IDictionary<string, string> parameters)
{
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
StringBuilder query = new StringBuilder("{");
Boolean first = true;
while (dem.MoveNext())
{
string key = dem.Current.Key;
string value = dem.Current.Value;
if (!string.IsNullOrEmpty(key))
{
Trace.WriteLine(String.Format("参数:{0} 值:{1}", key, value));
if (!first)
query.Append(",");
query.AppendFormat("\"{0}\":\"{1}\"", key, value);
first = false;
}
}
query.Append("}");
return query.ToString();
}
private T DoExecute<T>(IJdRequest<T> request, string accessToken, DateTime timestamp) where T : JdResponse
{
// 提前检查业务参数
try
{
request.Validate();
}
catch (JdException e)
{
return createErrorResponse<T>(e.ErrorCode, e.ErrorMsg);
}
// 添加协议级请求参数
JdDictionary txtParams = new JdDictionary();
string strParam = request.GetParamJson();
txtParams.Add(APP_PARAM, strParam);
txtParams.Add(METHOD, request.ApiName);
//API版本号,兼容开普勒接口调用,JOS接口不区分版本
txtParams.Add(VERSION, string.IsNullOrEmpty(request.ApiVersion)?"2.0":request.ApiVersion);
txtParams.Add(APP_KEY, appKey);
//txtParams.Add(FORMAT, format);
//txtParams.Add(PARTNER_ID, "top-sdk-net-20111024");
txtParams.Add(TIMESTAMP, timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff") + timestamp.ToString("zzzz").Replace(":", ""));
txtParams.Add(ACCESSTOKEN, accessToken);
// 添加签名参数
txtParams.Add(SIGN, JdUtils.SignJdRequest(txtParams, appSecret));
string serverUrl = this.serverUrl;
if (this.isJava)
{
txtParams.Remove(APP_PARAM);
serverUrl = serverUrl + "?" + WebUtils.BuildQuery(txtParams);
txtParams = new JdDictionary();
txtParams.Add(APP_PARAM, strParam);
}
// 是否需要上传文件
string body;
int nErr = 0;
retry:
Thread.Sleep(nErr * 500);
T rsp;
rsp = Activator.CreateInstance<T>();
if (request is IJdUploadRequest<T>)
{
IJdUploadRequest<T> uRequest = (IJdUploadRequest<T>)request;
IDictionary<string, FileItem> fileParams = JdUtils.CleanupDictionary(uRequest.GetFileParameters());
body = webUtils.DoPost(serverUrl, txtParams, fileParams);
}
else
{
body = webUtils.DoPost(serverUrl, txtParams, Proxy);
}
// 解释响应结果
rsp.Body = body;
{
if (FORMAT_JSON.Equals(format))
{
IJdParser<T> tp = new JdJsonParser<T>();
rsp = tp.Parse(body);
}
rsp.Body = body;
if ((rsp.ErrCode == "66") && nErr++ < 5)
{
//Trace.WriteLine(body);
goto retry;
}
}
// 追踪错误的请求
if (!disableTrace)
{
rsp.ReqUrl = webUtils.BuildGetUrl(this.serverUrl, txtParams);
if (rsp.IsError)
{
topLogger.Warn(rsp.ReqUrl + "\r\n" + rsp.Body);
}
}
return rsp;
}
private T createErrorResponse<T>(string errCode, string errMsg) where T : JdResponse
{
T rsp = Activator.CreateInstance<T>();
rsp.ErrCode = errCode;
rsp.ErrMsg = errMsg;
if (FORMAT_XML.Equals(format))
{
XmlDocument root = new XmlDocument();
XmlElement bodyE = root.CreateElement("error_response");
XmlElement codeE = root.CreateElement("code");
codeE.InnerText = errCode;
bodyE.AppendChild(codeE);
XmlElement msgE = root.CreateElement("msg");
msgE.InnerText = errMsg;
bodyE.AppendChild(msgE);
root.AppendChild(bodyE);
rsp.Body = root.OuterXml;
}
else
{
JObject errJson = new JObject();
errJson["error_response"] = new JObject();
errJson["error_response"]["code"] = errCode;
errJson["error_response"]["zh_desc"] = errMsg;
string body = errJson.ToString();
rsp.Body = body;
}
return rsp;
}
}
}