namespace DS.Module.HkOpenApi; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; public class HttpUtillib { /// /// 设置信息参数 /// /// 合作方APPKey /// 合作方APPSecret /// 平台IP /// 平台端口,默认HTTPS的443端口 /// 是否启用HTTPS协议,默认HTTPS /// public static void SetPlatformInfo(string appkey, string secret, string ip, int port = 443, bool isHttps = true) { _appkey = appkey; _secret = secret; _ip = ip; _port = port; _isHttps = isHttps; // 设置并发数,如不设置默认为2 ServicePointManager.DefaultConnectionLimit = 512; } /// /// HTTP GET请求 /// /// HTTP接口Url,不带协议和端口,如/artemis/api/resource/v1/cameras/indexCode?cameraIndexCode=a10cafaa777c49a5af92c165c95970e0 /// 请求超时时间,单位:秒 /// public static byte[] HttpGet(string uri, int timeout) { Dictionary header = new Dictionary(); // 初始化请求:组装请求头,设置远程证书自动验证通过 initRequest(header, uri, "", false); // build web request object StringBuilder sb = new StringBuilder(); sb.Append(_isHttps ? "https://" : "http://").Append(_ip).Append(":").Append(_port.ToString()).Append(uri); HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(sb.ToString()); req.KeepAlive = false; req.ProtocolVersion = HttpVersion.Version11; req.AllowAutoRedirect = false; // 不允许自动重定向 req.Method = "GET"; req.Timeout = timeout * 1000; // 传入是秒,需要转换成毫秒 req.Accept = header["Accept"]; req.ContentType = header["Content-Type"]; foreach (string headerKey in header.Keys) { if (headerKey.Contains("x-ca-")) { req.Headers.Add(headerKey + ":" + header[headerKey]); } } HttpWebResponse rsp = null; try { rsp = (HttpWebResponse)req.GetResponse(); if (HttpStatusCode.OK == rsp.StatusCode) { Stream rspStream = rsp.GetResponseStream(); // 响应内容字节流 StreamReader sr = new StreamReader(rspStream); string strStream = sr.ReadToEnd(); long streamLength = strStream.Length; byte[] response = System.Text.Encoding.UTF8.GetBytes(strStream); rsp.Close(); return response; } else if (HttpStatusCode.Found == rsp.StatusCode || HttpStatusCode.Moved == rsp.StatusCode) // 302/301 redirect { string reqUrl = rsp.Headers["Location"].ToString(); // 获取重定向URL WebRequest wreq = WebRequest.Create(reqUrl); // 重定向请求对象 WebResponse wrsp = wreq.GetResponse(); // 重定向响应 long streamLength = wrsp.ContentLength; // 重定向响应内容长度 Stream rspStream = wrsp.GetResponseStream(); // 响应内容字节流 byte[] response = new byte[streamLength]; rspStream.Read(response, 0, (int)streamLength); // 读取响应内容至byte数组 rspStream.Close(); rsp.Close(); return response; } rsp.Close(); } catch (WebException e) { if (rsp != null) { rsp.Close(); } } return null; } /// /// HTTP Post请求 /// /// HTTP接口Url,不带协议和端口,如/artemis/api/resource/v1/org/advance/orgList /// 请求参数 /// 请求超时时间,单位:秒 /// 请求结果 public static string HttpPost(string uri, string body, int timeout) { Dictionary header = new Dictionary(); // 初始化请求:组装请求头,设置远程证书自动验证通过 initRequest(header, uri, body, true); // build web request object StringBuilder sb = new StringBuilder(); sb.Append(_isHttps ? "https://" : "http://").Append(_ip).Append(":").Append(_port.ToString()).Append(uri); // 创建POST请求 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(sb.ToString()); req.KeepAlive = false; req.ProtocolVersion = HttpVersion.Version11; req.AllowAutoRedirect = false; // 不允许自动重定向 req.Method = "POST"; req.Timeout = timeout * 1000; // 传入是秒,需要转换成毫秒 req.Accept = header["Accept"]; req.ContentType = header["Content-Type"]; req.UserAgent = "PostmanRuntime/7.26.8"; foreach (string headerKey in header.Keys) { if (headerKey.Contains("x-ca-")) { req.Headers.Add(headerKey + ":" + header[headerKey]); } } byte[] data = Encoding.UTF8.GetBytes(body); req.ContentLength = data.Length; using (Stream reqStream = req.GetRequestStream()) { reqStream.Write(data, 0, data.Length); reqStream.Close(); } HttpWebResponse response = (HttpWebResponse)req.GetResponse(); Stream stream = response.GetResponseStream(); Encoding encode = Encoding.UTF8; StreamReader reader = new StreamReader(stream, encode); string content = reader.ReadToEnd(); stream.Close(); reader.Close(); return content; // if (!string.IsNullOrWhiteSpace(body)) // { // byte[] postBytes = Encoding.UTF8.GetBytes(body); // req.ContentLength = postBytes.Length; // Stream reqStream = null; // // try // { // reqStream = req.GetRequestStream(); // reqStream.Write(postBytes, 0, postBytes.Length); // reqStream.Close(); // } // catch (WebException e) // { // if (reqStream != null) // { // reqStream.Close(); // } // // return null; // } // } // // HttpWebResponse rsp = null; // try // { // rsp = (HttpWebResponse)req.GetResponse(); // if (HttpStatusCode.OK == rsp.StatusCode) // { // Stream rspStream = rsp.GetResponseStream(); // StreamReader sr = new StreamReader(rspStream); // string strStream = sr.ReadToEnd(); // long streamLength = strStream.Length; // byte[] response = System.Text.Encoding.UTF8.GetBytes(strStream); // rsp.Close(); // return response; // } // else if (HttpStatusCode.Found == rsp.StatusCode || // HttpStatusCode.Moved == rsp.StatusCode) // 302/301 redirect // { // try // { // string reqUrl = rsp.Headers["Location"].ToString(); // 如需要重定向URL,请自行修改接口返回此参数 // rsp.Close(); // WebRequest wreq = WebRequest.Create(reqUrl); // rsp = (HttpWebResponse)wreq.GetResponse(); // Stream rspStream = rsp.GetResponseStream(); // long streamLength = rsp.ContentLength; // int offset = 0; // byte[] response = new byte[streamLength]; // while (streamLength > 0) // { // int n = rspStream.Read(response, offset, (int)streamLength); // if (0 == n) // { // break; // } // // offset += n; // streamLength -= n; // } // // return response; // } // catch (Exception e) // { // rsp.Close(); // return null; // } // } // // rsp.Close(); // } // catch (WebException e) // { // if (rsp != null) // { // rsp.Close(); // } // } // return null; } private static void initRequest(Dictionary header, string url, string body, bool isPost) { // Accept // string accept = "application/json"; // "*/*"; string accept = "*/*"; // "*/*"; header.Add("Accept", accept); // ContentType string contentType = "application/json"; header.Add("Content-Type", contentType); // if (isPost) // { // // content-md5,be careful it must be lower case. // string contentMd5 = computeContentMd5(body); // header.Add("content-md5", contentMd5); // } // // x-ca-timestamp // string timestamp = // ((DateTime.Now.Ticks - // TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0)).Ticks) / 1000) // .ToString(); // header.Add("x-ca-timestamp", timestamp); // // // x-ca-nonce // string nonce = System.Guid.NewGuid().ToString(); // header.Add("x-ca-nonce", nonce); // x-ca-key header.Add("x-ca-key", _appkey); // build string to sign string strToSign = buildSignString(isPost ? "POST" : "GET", url, header); string signedStr = computeForHMACSHA256(strToSign, _secret); // x-ca-signature header.Add("x-ca-signature", signedStr); if (_isHttps) { // set remote certificate Validation auto pass ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(remoteCertificateValidate); // FIX:修复不同.Net版对一些SecurityProtocolType枚举支持情况不一致导致编译失败等问题,这里统一使用数值 // ServicePointManager.SecurityProtocol = (SecurityProtocolType)48 | (SecurityProtocolType)3072 | // (SecurityProtocolType)768 | (SecurityProtocolType)192 ; // ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; } } /// /// 计算content-md5 /// /// /// base64后的content-md5 private static string computeContentMd5(string body) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] result = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body)); return Convert.ToBase64String(result); } /// /// 远程证书验证 /// /// /// /// /// /// 验证是否通过,始终通过 private static bool remoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) { return true; } /// /// 计算HMACSHA265 /// /// 待计算字符串 /// 平台APPSecet /// HMAXH265计算结果字符串 private static string computeForHMACSHA256(string str, string secret) { var encoder = new System.Text.UTF8Encoding(); byte[] secretBytes = encoder.GetBytes(secret); byte[] strBytes = encoder.GetBytes(str); var opertor = new HMACSHA256(secretBytes); byte[] hashbytes = opertor.ComputeHash(strBytes); return Convert.ToBase64String(hashbytes); } /// /// 计算签名字符串 /// /// HTTP请求方法,如“POST” /// 接口Url,如/artemis/api/resource/v1/org/advance/orgList /// 请求头 /// 签名字符串 private static string buildSignString(string method, string url, Dictionary header) { StringBuilder sb = new StringBuilder(); sb.Append(method.ToUpper()).Append("\n"); if (null != header) { if (null != header["Accept"]) { sb.Append((string)header["Accept"]); sb.Append("\n"); } if (header.Keys.Contains("Content-MD5") && null != header["Content-MD5"]) { sb.Append((string)header["Content-MD5"]); sb.Append("\n"); } if (null != header["Content-Type"]) { sb.Append((string)header["Content-Type"]); sb.Append("\n"); } if (header.Keys.Contains("Date") && null != header["Date"]) { sb.Append((string)header["Date"]); sb.Append("\n"); } } // build and add header to sign string signHeader = buildSignHeader(header); sb.Append(signHeader); sb.Append(url); return sb.ToString(); } /// /// 计算签名头 /// /// 请求头 /// 签名头 private static string buildSignHeader(Dictionary header) { Dictionary sortedDicHeader = new Dictionary(); sortedDicHeader = header; var dic = from objDic in sortedDicHeader orderby objDic.Key ascending select objDic; StringBuilder sbSignHeader = new StringBuilder(); StringBuilder sb = new StringBuilder(); foreach (KeyValuePair kvp in dic) { if (kvp.Key.Replace(" ", "").Contains("x-ca-")) { sb.Append(kvp.Key + ":"); if (!string.IsNullOrWhiteSpace(kvp.Value)) { sb.Append(kvp.Value); } sb.Append("\n"); if (sbSignHeader.Length > 0) { sbSignHeader.Append(","); } sbSignHeader.Append(kvp.Key); } } header.Add("x-ca-signature-headers", sbSignHeader.ToString()); return sb.ToString(); } /// /// 平台ip /// private static string _ip; /// /// 平台端口 /// private static int _port = 443; /// /// 平台APPKey /// private static string _appkey; /// /// 平台APPSecret /// private static string _secret; /// /// 是否使用HTTPS协议 /// private static bool _isHttps = true; }