InvokeRestCenter.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. using Newtonsoft.Json;
  2. using Newtonsoft.Json.Linq;
  3. using Org.BouncyCastle.Asn1.Ocsp;
  4. using PTMedicalInsurance.Common;
  5. using PTMedicalInsurance.Variables;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Net;
  11. using System.Net.Http;
  12. using System.Net.Http.Headers;
  13. using System.Security.Cryptography;
  14. using System.Security.Policy;
  15. using System.Text;
  16. using System.Threading.Tasks;
  17. namespace PTMedicalInsurance.Helper
  18. {
  19. class InvokeRestCenter : IInvokeCenter
  20. {
  21. private static string GetRandomString(int length)
  22. {
  23. const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  24. var random = new Random();
  25. return new string(Enumerable.Repeat(chars, length)
  26. .Select(s => s[random.Next(s.Length)]).ToArray());
  27. }
  28. private static long GetCurrentUnixSeconds()
  29. {
  30. DateTimeOffset utcNow = DateTimeOffset.UtcNow.AddHours(8);
  31. return (long)(utcNow.ToUniversalTime().DateTime.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))).TotalSeconds;
  32. }
  33. private static string GetSHA256Str(string input)
  34. {
  35. using (SHA256 sha256Hash = SHA256.Create())
  36. {
  37. byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
  38. StringBuilder builder = new StringBuilder();
  39. foreach (byte b in bytes)
  40. {
  41. builder.Append(b.ToString("x2"));
  42. }
  43. return builder.ToString();
  44. }
  45. }
  46. public int Business(string inputData, ref string outputData, ref string pErrMsg)
  47. {
  48. outputData = "";
  49. pErrMsg = "";
  50. JObject joRtn = new JObject();
  51. try
  52. {
  53. if (string.IsNullOrEmpty(Global.curEvt.URL))
  54. {
  55. Global.curEvt.URL = Global.inf.centerURL;
  56. }
  57. //创建一个HTTP请求
  58. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Global.curEvt.URL);
  59. //Post请求方式
  60. request.Method = "POST";
  61. //设置头部信息
  62. string headstr = @"Bearer " + Global.curEvt.token;//市医保token
  63. request.Headers.Add("Authorization", headstr);
  64. //内容类型
  65. request.ContentType = "application/json";
  66. //设置参数,并进行URL编码
  67. string paraUrlCoded = inputData;//System.Web.HttpUtility.UrlEncode(jsonParas);
  68. byte[] payload;
  69. //将Json字符串转化为字节
  70. payload = System.Text.Encoding.UTF8.GetBytes(paraUrlCoded);
  71. //设置请求的ContentLength
  72. request.ContentLength = payload.Length;
  73. //发送请求,获得请求流
  74. Stream writer;
  75. writer = request.GetRequestStream();//获取用于写入请求数据的Stream对象
  76. //将请求参数写入流
  77. writer.Write(payload, 0, payload.Length);
  78. writer.Close();//关闭请求流
  79. HttpWebResponse response = null;
  80. try
  81. {
  82. //获得响应流
  83. response = (HttpWebResponse)request.GetResponse();
  84. }
  85. catch (WebException ex)
  86. {
  87. HttpWebResponse res = (HttpWebResponse)ex.Response;
  88. Stream myResponseStream = res.GetResponseStream();
  89. StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);
  90. string retString = myStreamReader.ReadToEnd();
  91. outputData = JsonHelper.setExceptionJson(-99, "异常返回", retString).ToString();
  92. return -1;
  93. }
  94. outputData = getResponseData(response);
  95. joRtn = JObject.Parse(outputData);//返回Json数据
  96. if (joRtn.ContainsKey("body"))
  97. {
  98. joRtn = (JObject)joRtn.GetValue("body");
  99. outputData = JsonHelper.toJsonString(joRtn);
  100. }
  101. return 0;
  102. }
  103. catch (Exception ex)
  104. {
  105. joRtn.Add("infcode", -1);
  106. joRtn.Add("err_msg", "调用中心服务异常invokeCenterService(1):" + ex.Message);
  107. outputData = JsonHelper.toJsonString(joRtn);
  108. return -1;
  109. }
  110. }
  111. public int BusinessExt(string inputData, ref string outputData, ref string pErrMsg)
  112. {
  113. return this.Business(inputData, ref outputData, ref pErrMsg);
  114. }
  115. //public int DownloadFile(string inputData, ref string outputData)
  116. //{
  117. // outputData = "";
  118. // string error = string.Empty; int errorCode = 0;
  119. // try
  120. // {
  121. // JObject jsonInParam = JObject.Parse(inputData);
  122. // // 去除外wrapper层便于通用
  123. // Utils.removeWrapper(jsonInParam);
  124. // string fileName = (string)jsonInParam["input"]["fsDownloadIn"]["filename"];
  125. // string filePath = Global.curEvt.path + "\\Download\\" + fileName;
  126. // //如果不存在目录,则创建目录
  127. // if (!Directory.Exists(Global.curEvt.path + "\\Download"))
  128. // {
  129. // //创建文件夹
  130. // DirectoryInfo dirInfo = Directory.CreateDirectory(Global.curEvt.path + "\\Download");
  131. // }
  132. // if (File.Exists(filePath))
  133. // {
  134. // File.Delete(filePath);
  135. // }
  136. // FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
  137. // //创建一个HTTP请求
  138. // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Global.curEvt.URL);
  139. // //Post请求方式
  140. // request.Method = "POST";
  141. // //设置参数,并进行URL编码
  142. // string paraUrlCoded = JsonHelper.toJsonString(jsonInParam);
  143. // byte[] payload;
  144. // //将Json字符串转化为字节
  145. // payload = System.Text.Encoding.UTF8.GetBytes(paraUrlCoded);
  146. // //设置请求的ContentLength
  147. // request.ContentLength = payload.Length;
  148. // Stream writer;
  149. // try
  150. // {
  151. // writer = request.GetRequestStream();//获取用于写入请求数据的Stream对象
  152. // }
  153. // catch (Exception)
  154. // {
  155. // writer = null;
  156. // errorCode = -100;
  157. // error = "连接服务器失败!";
  158. // }
  159. // //将请求参数写入流
  160. // writer.Write(payload, 0, payload.Length);
  161. // writer.Close();//关闭请求流
  162. // // String strValue = "";//strValue为http响应所返回的字符流
  163. // //发送请求并获取相应回应数据
  164. // HttpWebResponse response = request.GetResponse() as HttpWebResponse;
  165. // //直到request.GetResponse()程序才开始向目标网页发送Post请求
  166. // Stream responseStream = response.GetResponseStream();
  167. // //创建本地文件写入流
  168. // byte[] bArr = new byte[102400];
  169. // int iTotalSize = 0;
  170. // int size = responseStream.Read(bArr, 0, (int)bArr.Length);
  171. // while (size > 0)
  172. // {
  173. // iTotalSize += size;
  174. // fs.Write(bArr, 0, size);
  175. // size = responseStream.Read(bArr, 0, (int)bArr.Length);
  176. // }
  177. // fs.Close();
  178. // responseStream.Close();
  179. // dynamic joReturn = new JObject();
  180. // joReturn.errorCode = errorCode;
  181. // joReturn.errorMessage = error;
  182. // joReturn.filePath = filePath;
  183. // outputData = joReturn.ToString();
  184. // }
  185. // catch (Exception ex)
  186. // {
  187. // errorCode = -100;
  188. // error = ex.Message;
  189. // dynamic joReturn = new JObject();
  190. // joReturn.errorCode = errorCode;
  191. // joReturn.errorMessage = error;
  192. // outputData = joReturn.ToString();
  193. // return -1;
  194. // }
  195. // finally
  196. // {
  197. // Global.writeLog("DownloadCenterFile" + "(" + Global.curEvt.URL + ")", inputData, outputData);
  198. // }
  199. // return 0;
  200. //}
  201. public int DownloadFile(string inputData, ref string outputData)
  202. {
  203. outputData = "";
  204. int errorCode = 0;
  205. string error = string.Empty;
  206. string filePath = "";
  207. HttpWebResponse response = null;
  208. FileStream fs = null;
  209. try
  210. {
  211. JObject jsonInParam = JObject.Parse(inputData);
  212. Utils.removeWrapper(jsonInParam);
  213. string fileName = (string)jsonInParam["input"]["fsDownloadIn"]["filename"];
  214. if (string.IsNullOrWhiteSpace(fileName))
  215. {
  216. errorCode = -101;
  217. error = "文件名不能为空";
  218. throw new ArgumentException(error);
  219. }
  220. string downloadDir = Path.Combine(Global.curEvt.path, "Download");
  221. filePath = Path.Combine(downloadDir, fileName);
  222. // 创建目录
  223. if (!Directory.Exists(downloadDir))
  224. {
  225. Directory.CreateDirectory(downloadDir);
  226. }
  227. // 删除旧文件
  228. if (File.Exists(filePath))
  229. {
  230. File.Delete(filePath);
  231. }
  232. // 准备 POST 请求
  233. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Global.inf.downURL);
  234. request.Method = "POST";
  235. request.ContentType = "application/json; charset=utf-8";
  236. //request.UserAgent = "DownloadClient/1.0";
  237. // 添加 Authorization 头
  238. string headstr = @"Bearer " + Global.curEvt.token;//市医保token
  239. request.Headers.Add("Authorization", headstr);
  240. string requestBody = JsonHelper.toJsonString(jsonInParam);
  241. byte[] payload = Encoding.UTF8.GetBytes(requestBody);
  242. request.ContentLength = payload.Length;
  243. // 写入请求体
  244. using (Stream requestStream = request.GetRequestStream())
  245. {
  246. requestStream.Write(payload, 0, payload.Length);
  247. }
  248. // 获取响应
  249. response = (HttpWebResponse)request.GetResponse();
  250. // ✅ 关键:记录状态码和 Content-Type
  251. string statusCode = $"{(int)response.StatusCode} {response.StatusCode}";
  252. string contentType = response.ContentType?.ToLower() ?? "";
  253. Global.writeLog("DownloadFile_Response",
  254. $"StatusCode: {statusCode}\r\n" ,
  255. $"Content-Type: {contentType}");
  256. // ✅ 判断是否可能是错误响应(即使 200 OK)
  257. bool isJsonOrError = contentType.Contains("json") ||
  258. contentType.Contains("text") ||
  259. response.ContentLength < 1024; // 小文件很可能是错误信息
  260. using (Stream responseStream = response.GetResponseStream())
  261. using (fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
  262. {
  263. byte[] buffer = new byte[8192];
  264. int bytesRead;
  265. long totalBytesRead = 0;
  266. MemoryStream firstChunk = new MemoryStream(); // 仅缓存前 1KB 用于判断
  267. while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
  268. {
  269. // 累计写入文件
  270. fs.Write(buffer, 0, bytesRead);
  271. totalBytesRead += bytesRead;
  272. // ✅ 仅在开始时缓存前 1KB 用于错误判断
  273. if (totalBytesRead <= 1024)
  274. {
  275. firstChunk.Write(buffer, 0, bytesRead);
  276. }
  277. }
  278. // 文件已完整写入磁盘,现在检查前 1KB 是否为错误信息
  279. if (isJsonOrError || totalBytesRead < 1024)
  280. {
  281. string firstContent = Encoding.UTF8.GetString(firstChunk.ToArray());
  282. firstContent = firstContent.Trim();
  283. // 判断是否为 JSON 错误
  284. if (firstContent.StartsWith("{") &&
  285. (firstContent.Contains("\"code\"") ||
  286. firstContent.Contains("err_msg")))
  287. {
  288. try
  289. {
  290. var errorObj = JObject.Parse(firstContent);
  291. int? errCode = errorObj["code"]?.Value<int?>() ??
  292. errorObj["infcode"]?.Value<int?>();
  293. if (errCode != null && errCode != 0 && errCode != 200)
  294. {
  295. string errMsg = errorObj["err_msg"]?.Value<string>() ??
  296. errorObj["errorMessage"]?.Value<string>() ??
  297. "Unknown error";
  298. throw new Exception($"业务错误 [{errCode}]: {errMsg}");
  299. }
  300. }
  301. catch (JsonException)
  302. {
  303. // 不是 JSON,但内容可疑
  304. throw new Exception("服务器返回错误内容,非有效文件: " + firstContent);
  305. }
  306. }
  307. }
  308. }
  309. // ✅ 成功:返回结果
  310. dynamic joReturn = new JObject();
  311. joReturn.errorCode = 0;
  312. joReturn.errorMessage = "";
  313. joReturn.filePath = filePath;
  314. joReturn.fileSize = new FileInfo(filePath).Length;
  315. outputData = joReturn.ToString();
  316. return 0;
  317. }
  318. catch (WebException webEx)
  319. {
  320. Global.writeLog($"进入异常 + {webEx}");
  321. // 处理 HTTP 层错误
  322. if (webEx.Response is HttpWebResponse errResponse)
  323. {
  324. using (var sr = new StreamReader(errResponse.GetResponseStream()))
  325. {
  326. string serverMsg = sr.ReadToEnd();
  327. errorCode = (int)errResponse.StatusCode;
  328. error = $"请求失败 :{webEx} [{errResponse.StatusCode}]: {serverMsg}";
  329. }
  330. }
  331. else
  332. {
  333. errorCode = -100;
  334. error = "连接服务器失败: " + webEx.Message;
  335. }
  336. }
  337. catch (JsonException jsonEx)
  338. {
  339. errorCode = -200;
  340. error = "输入数据格式错误: " + jsonEx.Message;
  341. }
  342. catch (UnauthorizedAccessException accEx)
  343. {
  344. errorCode = -300;
  345. error = "无权访问文件或目录: " + accEx.Message;
  346. }
  347. catch (IOException ioEx)
  348. {
  349. errorCode = -400;
  350. error = "文件操作失败: " + ioEx.Message;
  351. }
  352. catch (Exception ex) when (errorCode == 0)
  353. {
  354. errorCode = -999;
  355. error = "未知错误: " + ex.Message;
  356. }
  357. finally
  358. {
  359. response?.Close();
  360. if (string.IsNullOrEmpty(outputData))
  361. {
  362. dynamic joReturn = new JObject();
  363. joReturn.errorCode = errorCode;
  364. joReturn.errorMessage = error;
  365. if (!string.IsNullOrEmpty(filePath)) joReturn.filePath = filePath;
  366. outputData = joReturn.ToString();
  367. }
  368. Global.writeLog($"DownloadFile({Global.inf.downURL})", inputData, outputData);
  369. }
  370. return -1;
  371. }
  372. public void Test1(string DownInput)
  373. {
  374. HttpClient httpClient = null;
  375. HttpResponseMessage response = null;
  376. try
  377. {
  378. // 创建 HttpClient 并设置超时
  379. var handler = new HttpClientHandler();
  380. httpClient = new HttpClient(handler)
  381. {
  382. Timeout = TimeSpan.FromSeconds(10) // 连接 + 响应超时
  383. };
  384. // 构造请求内容
  385. var content = new StringContent(DownInput, Encoding.UTF8, "text/plain");
  386. content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
  387. // 添加 Authorization 头
  388. string headstr = "Bearer " + Global.curEvt.token; // 市医保 token
  389. //httpClient.DefaultRequestHeaders.Authorization =
  390. // new AuthenticationHeaderValue("Bearer", Global.curEvt.token);
  391. // 或者使用:
  392. httpClient.DefaultRequestHeaders.Add("Authorization", headstr);
  393. // 发送 POST 请求(同步等待)
  394. response = httpClient.PostAsync(Global.inf.centerURL, content).GetAwaiter().GetResult();
  395. // 检查状态码
  396. if (response.StatusCode != System.Net.HttpStatusCode.OK)
  397. {
  398. throw new HttpRequestException($"HTTP 请求失败,状态码: {response.StatusCode}");
  399. }
  400. // 读取 Content-Type 判断响应类型
  401. var contentType = response.Content.Headers.ContentType?.MediaType ?? "";
  402. if (contentType.Contains("application/octet-stream"))
  403. {
  404. // 情况1:返回的是文件流(二进制流)
  405. using (var responseStream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
  406. using (var fileStream = new FileStream("testDownload.txt", FileMode.Create, FileAccess.Write))
  407. {
  408. responseStream.CopyTo(fileStream);
  409. }
  410. Global.writeLog("文件已下载到 testDownload.txt");
  411. }
  412. else
  413. {
  414. // 情况2:返回的是字符串(如 JSON)
  415. string result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
  416. Global.writeLog("Test1:" + result);
  417. }
  418. }
  419. catch (AggregateException ax) when (ax.InnerException is TimeoutException)
  420. {
  421. throw new TimeoutException("请求超时", ax.InnerException);
  422. }
  423. catch (HttpRequestException e)
  424. {
  425. throw new Exception("HTTP 请求异常: " + e.Message, e);
  426. }
  427. catch (Exception e)
  428. {
  429. throw new Exception("发生未知错误: " + e.Message, e);
  430. }
  431. finally
  432. {
  433. // 手动释放资源
  434. response?.Dispose();
  435. httpClient?.Dispose();
  436. }
  437. }
  438. public int Init(ref string pErrMsg)
  439. {
  440. return 0;
  441. }
  442. public int UploadFile(string inputData, ref string outputData, ref string pErrMsg)
  443. {
  444. throw new NotImplementedException();
  445. }
  446. private string getResponseData(HttpWebResponse response)
  447. {
  448. string data = "";
  449. if (response != null)
  450. {
  451. Stream s = response.GetResponseStream();
  452. StreamReader sRead = new StreamReader(s,Encoding.GetEncoding("UTF-8"));
  453. data = sRead.ReadToEnd();
  454. sRead.Close();
  455. response.Close();
  456. }
  457. return data;
  458. }
  459. }
  460. }