HttpClientHelper.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net.Http;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Newtonsoft.Json;
  8. public class HttpClientHelper
  9. {
  10. // 单例实例
  11. private static readonly Lazy<HttpClientHelper> _instance = new Lazy<HttpClientHelper>(() => new HttpClientHelper());
  12. // 全局访问属性
  13. public static HttpClientHelper Instance => _instance.Value;
  14. // 内部使用的 HttpClient
  15. private readonly HttpClient _httpClient;
  16. // 私有构造函数,防止外部实例化
  17. private HttpClientHelper()
  18. {
  19. _httpClient = new HttpClient();
  20. }
  21. // 定义内容类型枚举
  22. public enum ContentType
  23. {
  24. Json,
  25. FormData,
  26. Text,
  27. Xml,
  28. Plain,
  29. x_www_form
  30. }
  31. public void SetBaseAddress(string baseAddress)
  32. {
  33. _httpClient.BaseAddress = new Uri(baseAddress);
  34. }
  35. // 发送请求的方法(保持原有逻辑不变)
  36. public async Task<ApiResponse<string>> SendRequestAsync(
  37. HttpMethod method,
  38. string requestUri,
  39. object body = null,
  40. Dictionary<string, string> headers = null,
  41. ContentType contentType = ContentType.Json)
  42. {
  43. var request = new HttpRequestMessage
  44. {
  45. Method = method,
  46. RequestUri = new Uri(_httpClient.BaseAddress, requestUri)
  47. };
  48. if (headers != null)
  49. {
  50. foreach (var header in headers)
  51. {
  52. request.Headers.Add(header.Key, header.Value);
  53. }
  54. }
  55. if (body != null)
  56. {
  57. switch (contentType)
  58. {
  59. case ContentType.Json:
  60. request.Content = new StringContent(
  61. body.ToString(),
  62. Encoding.UTF8,
  63. "application/json");
  64. break;
  65. case ContentType.FormData:
  66. if (body is Dictionary<string, string> formData)
  67. {
  68. var multipartContent = new MultipartFormDataContent();
  69. foreach (var pair in formData)
  70. {
  71. multipartContent.Add(new StringContent(pair.Value, Encoding.UTF8),
  72. $"\"{pair.Key}\""); // 注意 Key 要加引号
  73. }
  74. request.Content = multipartContent;
  75. }
  76. else
  77. {
  78. return ApiResponse<string>.Failure("FormData body must be Dictionary<string, string>", 400);
  79. }
  80. break;
  81. case ContentType.Text:
  82. request.Content = new StringContent(
  83. body.ToString(),
  84. Encoding.UTF8,
  85. "text/plain");
  86. break;
  87. case ContentType.Xml:
  88. request.Content = new StringContent(
  89. body.ToString(),
  90. Encoding.UTF8,
  91. "application/xml");
  92. break;
  93. case ContentType.Plain:
  94. request.Content = new StringContent(
  95. body.ToString(),
  96. Encoding.UTF8,
  97. "text/plain");
  98. break;
  99. case ContentType.x_www_form:
  100. if (body is Dictionary<string, string> xformData)
  101. {
  102. var formContent = new FormUrlEncodedContent(xformData);
  103. request.Content = formContent;
  104. }
  105. else
  106. {
  107. return ApiResponse<string>.Failure("FormData body must be Dictionary<string, string>", 400);
  108. }
  109. break;
  110. default:
  111. return ApiResponse<string>.Failure("Unsupported content type", 400);
  112. }
  113. }
  114. HttpResponseMessage response;
  115. try
  116. {
  117. response = await _httpClient.SendAsync(request);
  118. }
  119. catch (Exception ex)
  120. {
  121. return ApiResponse<string>.Failure($"Network error: {ex.Message}", 503);
  122. }
  123. var responseBody = await response.Content.ReadAsStringAsync();
  124. if (response.IsSuccessStatusCode)
  125. {
  126. return ApiResponse<string>.Success(responseBody, (int)response.StatusCode);
  127. }
  128. else
  129. {
  130. return ApiResponse<string>.Failure(responseBody, (int)response.StatusCode);
  131. }
  132. }
  133. public ApiResponse<string> SendRequest(
  134. HttpMethod method,
  135. string requestUri,
  136. object body = null,
  137. Dictionary<string, string> headers = null,
  138. ContentType contentType = ContentType.Json)
  139. {
  140. var request = new HttpRequestMessage
  141. {
  142. Method = method,
  143. RequestUri = new Uri(_httpClient.BaseAddress, requestUri)
  144. };
  145. if (headers != null)
  146. {
  147. foreach (var header in headers)
  148. {
  149. request.Headers.Add(header.Key, header.Value);
  150. }
  151. }
  152. if (body != null)
  153. {
  154. switch (contentType)
  155. {
  156. case ContentType.Json:
  157. request.Content = new StringContent(
  158. body.ToString(),
  159. Encoding.UTF8,
  160. "application/json");
  161. break;
  162. case ContentType.FormData:
  163. if (body is Dictionary<string, string> formData)
  164. {
  165. var multipartContent = new MultipartFormDataContent();
  166. foreach (var pair in formData)
  167. {
  168. multipartContent.Add(
  169. new StringContent(pair.Value, Encoding.UTF8),
  170. $"\"{pair.Key}\""); // 注意 key 加引号
  171. }
  172. request.Content = multipartContent;
  173. }
  174. else
  175. {
  176. return ApiResponse<string>.Failure("FormData body must be Dictionary<string, string>", 400);
  177. }
  178. break;
  179. case ContentType.x_www_form:
  180. if (body is Dictionary<string, string> xformData)
  181. {
  182. request.Content = new FormUrlEncodedContent(xformData);
  183. }
  184. else
  185. {
  186. return ApiResponse<string>.Failure("FormData body must be Dictionary<string, string>", 400);
  187. }
  188. break;
  189. case ContentType.Text:
  190. case ContentType.Plain:
  191. request.Content = new StringContent(
  192. body.ToString(),
  193. Encoding.UTF8,
  194. "text/plain");
  195. break;
  196. case ContentType.Xml:
  197. request.Content = new StringContent(
  198. body.ToString(),
  199. Encoding.UTF8,
  200. "application/xml");
  201. break;
  202. default:
  203. return ApiResponse<string>.Failure("Unsupported content type", 400);
  204. }
  205. }
  206. HttpResponseMessage response;
  207. try
  208. {
  209. // ✅ 使用 SendAsync().Result 模拟同步发送
  210. response = _httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead).Result;
  211. }
  212. catch (Exception ex)
  213. {
  214. return ApiResponse<string>.Failure($"Network error: {ex.Message}", 503);
  215. }
  216. var responseBody = response.Content.ReadAsStringAsync().Result;
  217. if (response.IsSuccessStatusCode)
  218. {
  219. return ApiResponse<string>.Success(responseBody, (int)response.StatusCode);
  220. }
  221. else
  222. {
  223. return ApiResponse<string>.Failure(responseBody, (int)response.StatusCode);
  224. }
  225. }
  226. public class ApiResponse<T>
  227. {
  228. public bool IsSuccess { get; set; }
  229. public int StatusCode { get; set; }
  230. public string ErrorMessage { get; set; }
  231. public T Result { get; set; }
  232. public static ApiResponse<T> Success(T result, int statusCode)
  233. {
  234. return new ApiResponse<T> { IsSuccess = true, StatusCode = statusCode, Result = result };
  235. }
  236. public static ApiResponse<T> Failure(string message, int statusCode)
  237. {
  238. return new ApiResponse<T> { IsSuccess = false, StatusCode = statusCode, ErrorMessage = message };
  239. }
  240. }
  241. }