using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Cryptography; using System.Text; using System.Threading; using POSV.Utils; namespace POSV.Dianping { public class MeituanCouponUtils { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private static object _lock = new object(); private static HttpClient httpClient = null; private static MeituanCouponUtils _instance = null; private static string baseUrl = "https://open-api.dianping.com"; private static string version = "2.0"; public static string TEST_APPKEY = "7e75fa08b18f5fcd867e1d1cd58e38ea72fb33c1"; public static string TEST_APPSECRET = "34d4da25d45b4f812ab99a7ab608b50e7d3bbf10"; public static MeituanCouponUtils Instance { get { if (_instance == null) { lock (_lock) { //remove limits from service point manager ServicePointManager.MaxServicePoints = 10000; ServicePointManager.DefaultConnectionLimit = 10000; ServicePointManager.CheckCertificateRevocationList = true; ServicePointManager.Expect100Continue = false; ServicePointManager.MaxServicePointIdleTime = 1000 * 30; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; ServicePointManager.UseNagleAlgorithm = false; ServicePointManager.DnsRefreshTimeout = 0; //提升系统外联的最大并发web访问数 ServicePointManager.DefaultConnectionLimit = 1024; ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 // | SecurityProtocolType.Tls // | (SecurityProtocolType)0x300 //Tls11 // | (SecurityProtocolType)0xC00; //Tls12 //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls // | (SecurityProtocolType)0x300 //Tls11 // | (SecurityProtocolType)0xC00; //Tls12 var handler = new HttpClientHandler(); if (handler.SupportsAutomaticDecompression) { handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; } handler.Proxy = null; handler.UseProxy = false; handler.UseDefaultCredentials = false; httpClient = new HttpClient(handler); Interlocked.CompareExchange(ref httpClient, new HttpClient(handler) { BaseAddress = new Uri(baseUrl) }, null); httpClient.DefaultRequestHeaders.Connection.Add("Keep-Alive"); httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36"); httpClient.DefaultRequestHeaders.Add("Accept", "*/*"); httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate"); //声明给服务器,客户端支持gzip解压 httpClient.DefaultRequestHeaders.Add("Accept-Language", "zh-cn,en-us;q=0.7,en;q=0.3"); httpClient.DefaultRequestHeaders.Add("Pragma", "no-cache"); httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache"); httpClient.DefaultRequestHeaders.Add("ES-API-VERSION", "1.0.0"); httpClient.DefaultRequestHeaders.ExpectContinue = false; httpClient.Timeout = new TimeSpan(0, 0, 20); _instance = new MeituanCouponUtils(); } } return _instance; } } public string PostAsync(string requestUrl, SortedList parameters) { Stopwatch watch = Stopwatch.StartNew(); try { string appKey = Global.StoreInfo.StoreInfoMessage.MeituanAppKey; string appSecret = Global.StoreInfo.StoreInfoMessage.MeituanAppSecret; if (!string.IsNullOrEmpty(appKey)) { appKey = appKey.Trim(); } if (!string.IsNullOrEmpty(appSecret)) { appSecret = appSecret.Trim(); } var stringParams = JsonUtils.Serialize(parameters); var content = new StringContent(stringParams, Encoding.UTF8, "application/json"); string timestamp = this.GetTimestamp(); StringBuilder sb = new StringBuilder(); sb.Append(baseUrl).Append(requestUrl); sb.Append("?"); sb.Append("appKey").Append("=").Append(appKey).Append("&"); sb.Append("ts").Append("=").Append(timestamp).Append("&"); sb.Append("version").Append("=").Append(version).Append("&"); var sign = this.Sign(appKey, appSecret, timestamp, version, parameters); sb.Append("sign").Append("=").Append(sign); string url = sb.ToString(); var task = httpClient.PostAsync(url, content); task.Result.EnsureSuccessStatusCode(); HttpResponseMessage response = task.Result; var result = response.Content.ReadAsStringAsync(); return result.Result; } catch (Exception ex) { string message = "调用PostAsync方法发生错误,XP系统不支持"; logger.Error(ex, message); throw new Exception(message); } finally { logger.Info("耗时<{0}>毫秒", watch.ElapsedMilliseconds); } } public Tuple OrderConsume(TuangouOrderConsumeRequest request) { Tuple result = null; try { var parameters = new SortedList(); parameters.Add("vendorOrderId", request.VendorOrderId); parameters.Add("totalAmount", request.TotalAmount); parameters.Add("orderSkus", request.OrderSkus); parameters.Add("couponCode", request.CouponCode); parameters.Add("vendorShopId", request.VendorShopId); parameters.Add("eId", request.EId); parameters.Add("eName", request.EName); string response = Instance.PostAsync("/tuangou/coupon/orderConsume", parameters); var data = JsonUtils.Deserialize>(response); if (data.Code == 200) { result = new Tuple(true, data.Message, data.Content); } else { result = new Tuple(false, string.Format("{0}<{1}>", data.Message, data.Code), null); } } catch (Exception ex) { logger.Error(ex, "券码核销异常"); result = new Tuple(false, "券码核销异常,本次操作无效", null); } return result; } public Tuple OrdeCancel(CouponCancelRequest request) { Tuple result = null; try { var parameters = new SortedList(); parameters.Add("couponCode", request.CouponCode); parameters.Add("vendorShopId", request.VendorShopId); parameters.Add("eId", request.EId); parameters.Add("eName", request.EName); string response = Instance.PostAsync("/tuangou/coupon/cancel", parameters); var data = JsonUtils.Deserialize>(response); if (data.Code == 200) { result = new Tuple(true, data.Message, data.Content); } else { result = new Tuple(false, string.Format("{0}<{1}>", data.Message, data.Code), null); } } catch (Exception ex) { logger.Error(ex, "撤销验券异常"); result = new Tuple(false, "撤销验券异常,本次操作无效", null); } return result; } /// /// 券状态查询,通过该接口可获取到团购券的基本信息。 /// /// /// /// /// public Tuple CouponQuery(CouponStatusQueryRequest request) { Tuple result = null; try { var parameters = new SortedList(); parameters.Add("couponCode", request.CouponCode); parameters.Add("vendorShopId", request.VendorShopId); string response = Instance.PostAsync("/tuangou/coupon/status/query", parameters); var data = JsonUtils.Deserialize>(response); if(data.Code == 200) { result = new Tuple(true, data.Message, data.Content); } else { result = new Tuple(false, string.Format("{0}<{1}>",data.Message,data.Code), null); } } catch (Exception ex) { logger.Error(ex, "查询券状态异常"); result = new Tuple(false, "查询券状态异常,本次操作无效", null); } return result; } public Tuple QueryLocalListByDate(CouponLocalRecordRequest request) { Tuple result = null; try { var parameters = new SortedList(); parameters.Add("vendorShopId", request.VendorShopId); parameters.Add("date", request.Date); parameters.Add("offset", request.Offset); parameters.Add("limit", request.Limit); if(request.VendorOrderId != null && request.VendorOrderId.Count() > 0) { parameters.Add("vendorOrderId", request.VendorOrderId); } string response = Instance.PostAsync("/tuangou/coupon/queryLocalListByDate", parameters); var data = JsonUtils.Deserialize>(response); if (data.Code == 200) { result = new Tuple(true, data.Message, data.Content); } else { result = new Tuple(false, string.Format("{0}<{1}>", data.Message, data.Code), null); } } catch (Exception ex) { logger.Error(ex, "查询门店验券历史异常"); result = new Tuple(false, "查询门店验券历史异常,本次操作无效", null); } return result; } /// /// 获取当前时间戳,兼容Java服务端 /// /// public string GetTimestamp() { TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks); return Convert.ToString((long)ts.TotalMilliseconds); } public string Sign(string appKey, string appSecret,string ts,string version, SortedList param) { StringBuilder sb = new StringBuilder(); sb.Append(appSecret); sb.Append("appKey").Append(appKey); sb.Append("ts").Append(ts); sb.Append("version").Append(version); if(param == null) { param = new SortedList(); } sb.Append(JsonUtils.Serialize(param)); logger.Info("签名字符串:{0}", sb.ToString()); SHA1 sha1 = new SHA1CryptoServiceProvider();//建立一个SHA1 byte[] source = Encoding.UTF8.GetBytes(sb.ToString());//将字符串转为Byte[] byte[] crypto = sha1.ComputeHash(source);//进行SHA1加密 return ByteArrayToHexString(crypto);//把加密后的字符串从Byte[]转为字符串 } /// /// 字节数组转十六进制字符串 /// /// /// public string ByteArrayToHexString(byte[] data) { StringBuilder sb = new StringBuilder(data.Length * 3); foreach (byte b in data) { sb.Append(Convert.ToString(b, 16).PadLeft(2, '0')); } return sb.ToString().ToLower(); } } }