WebUtils.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Compression;
  5. using System.Net;
  6. using System.Net.Security;
  7. using System.Security.Cryptography.X509Certificates;
  8. using System.Text;
  9. using System.Web;
  10. namespace Top.Api.Util
  11. {
  12. /// <summary>
  13. /// 网络工具类。
  14. /// </summary>
  15. public sealed class WebUtils
  16. {
  17. private int _timeout = 20000;
  18. private int _readWriteTimeout = 60000;
  19. private bool _ignoreSSLCheck = true;
  20. private bool _disableWebProxy = false;
  21. /// <summary>
  22. /// 等待请求开始返回的超时时间
  23. /// </summary>
  24. public int Timeout
  25. {
  26. get { return this._timeout; }
  27. set { this._timeout = value; }
  28. }
  29. /// <summary>
  30. /// 等待读取数据完成的超时时间
  31. /// </summary>
  32. public int ReadWriteTimeout
  33. {
  34. get { return this._readWriteTimeout; }
  35. set { this._readWriteTimeout = value; }
  36. }
  37. /// <summary>
  38. /// 是否忽略SSL检查
  39. /// </summary>
  40. public bool IgnoreSSLCheck
  41. {
  42. get { return this._ignoreSSLCheck; }
  43. set { this._ignoreSSLCheck = value; }
  44. }
  45. /// <summary>
  46. /// 是否禁用本地代理
  47. /// </summary>
  48. public bool DisableWebProxy
  49. {
  50. get { return this._disableWebProxy; }
  51. set { this._disableWebProxy = value; }
  52. }
  53. /// <summary>
  54. /// 执行HTTP POST请求。
  55. /// </summary>
  56. /// <param name="url">请求地址</param>
  57. /// <param name="textParams">请求文本参数</param>
  58. /// <returns>HTTP响应</returns>
  59. public string DoPost(string url, IDictionary<string, string> textParams)
  60. {
  61. return DoPost(url, textParams, null);
  62. }
  63. /// <summary>
  64. /// 执行HTTP POST请求。
  65. /// </summary>
  66. /// <param name="url">请求地址</param>
  67. /// <param name="textParams">请求文本参数</param>
  68. /// <param name="headerParams">请求头部参数</param>
  69. /// <returns>HTTP响应</returns>
  70. public string DoPost(string url, IDictionary<string, string> textParams, IDictionary<string, string> headerParams)
  71. {
  72. HttpWebRequest req = GetWebRequest(url, "POST", headerParams);
  73. req.ContentType = "application/x-www-form-urlencoded;charset=utf-8";
  74. byte[] postData = Encoding.UTF8.GetBytes(BuildQuery(textParams));
  75. System.IO.Stream reqStream = req.GetRequestStream();
  76. reqStream.Write(postData, 0, postData.Length);
  77. reqStream.Close();
  78. HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
  79. Encoding encoding = GetResponseEncoding(rsp);
  80. return GetResponseAsString(rsp, encoding);
  81. }
  82. /// <summary>
  83. /// 执行HTTP GET请求。
  84. /// </summary>
  85. /// <param name="url">请求地址</param>
  86. /// <param name="textParams">请求文本参数</param>
  87. /// <returns>HTTP响应</returns>
  88. public string DoGet(string url, IDictionary<string, string> textParams)
  89. {
  90. return DoGet(url, textParams, null);
  91. }
  92. /// <summary>
  93. /// 执行HTTP GET请求。
  94. /// </summary>
  95. /// <param name="url">请求地址</param>
  96. /// <param name="textParams">请求文本参数</param>
  97. /// <param name="headerParams">请求头部参数</param>
  98. /// <returns>HTTP响应</returns>
  99. public string DoGet(string url, IDictionary<string, string> textParams, IDictionary<string, string> headerParams)
  100. {
  101. if (textParams != null && textParams.Count > 0)
  102. {
  103. url = BuildRequestUrl(url, textParams);
  104. }
  105. HttpWebRequest req = GetWebRequest(url, "GET", headerParams);
  106. req.ContentType = "application/x-www-form-urlencoded;charset=gbk";
  107. HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
  108. Encoding encoding = GetResponseEncoding(rsp);
  109. return GetResponseAsString(rsp, encoding);
  110. }
  111. /// <summary>
  112. /// 执行带文件上传的HTTP POST请求。
  113. /// </summary>
  114. /// <param name="url">请求地址</param>
  115. /// <param name="textParams">请求文本参数</param>
  116. /// <param name="fileParams">请求文件参数</param>
  117. /// <param name="headerParams">请求头部参数</param>
  118. /// <returns>HTTP响应</returns>
  119. public string DoPost(string url, IDictionary<string, string> textParams, IDictionary<string, FileItem> fileParams, IDictionary<string, string> headerParams)
  120. {
  121. // 如果没有文件参数,则走普通POST请求
  122. if (fileParams == null || fileParams.Count == 0)
  123. {
  124. return DoPost(url, textParams, headerParams);
  125. }
  126. string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
  127. HttpWebRequest req = GetWebRequest(url, "POST", headerParams);
  128. req.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;
  129. System.IO.Stream reqStream = req.GetRequestStream();
  130. byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
  131. byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
  132. if(textParams != null)
  133. {
  134. // 组装文本请求参数
  135. string textTemplate = "Content-Disposition:form-data;name=\"{0}\"\r\nContent-Type:text/plain\r\n\r\n{1}";
  136. foreach (KeyValuePair<string, string> kv in textParams)
  137. {
  138. string textEntry = string.Format(textTemplate, kv.Key, kv.Value);
  139. byte[] itemBytes = Encoding.UTF8.GetBytes(textEntry);
  140. reqStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
  141. reqStream.Write(itemBytes, 0, itemBytes.Length);
  142. }
  143. }
  144. // 组装文件请求参数
  145. string fileTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type:{2}\r\n\r\n";
  146. foreach (KeyValuePair<string, FileItem> kv in fileParams)
  147. {
  148. string key = kv.Key;
  149. FileItem fileItem = kv.Value;
  150. if (!fileItem.IsValid())
  151. {
  152. throw new ArgumentException("FileItem is invalid");
  153. }
  154. string fileEntry = string.Format(fileTemplate, key, fileItem.GetFileName(), fileItem.GetMimeType());
  155. byte[] itemBytes = Encoding.UTF8.GetBytes(fileEntry);
  156. reqStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
  157. reqStream.Write(itemBytes, 0, itemBytes.Length);
  158. fileItem.Write(reqStream);
  159. }
  160. reqStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
  161. reqStream.Close();
  162. HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
  163. Encoding encoding = GetResponseEncoding(rsp);
  164. return GetResponseAsString(rsp, encoding);
  165. }
  166. /// <summary>
  167. /// 执行带body体的POST请求。
  168. /// </summary>
  169. /// <param name="url">请求地址,含URL参数</param>
  170. /// <param name="body">请求body体字节流</param>
  171. /// <param name="contentType">body内容类型</param>
  172. /// <param name="headerParams">请求头部参数</param>
  173. /// <returns>HTTP响应</returns>
  174. public string DoPost(string url, byte[] body, string contentType, IDictionary<string, string> headerParams)
  175. {
  176. HttpWebRequest req = GetWebRequest(url, "POST", headerParams);
  177. req.ContentType = contentType;
  178. if (body != null)
  179. {
  180. System.IO.Stream reqStream = req.GetRequestStream();
  181. reqStream.Write(body, 0, body.Length);
  182. reqStream.Close();
  183. }
  184. HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
  185. Encoding encoding = GetResponseEncoding(rsp);
  186. return GetResponseAsString(rsp, encoding);
  187. }
  188. /// <summary>
  189. /// 调用请求
  190. /// content type: application/json
  191. /// </summary>
  192. /// <returns>The post with json.</returns>
  193. /// <param name="url">URL.</param>
  194. /// <param name="textParams">Text parameters.</param>
  195. /// <param name="headerParams">Header parameters.</param>
  196. public string DoPostWithJson(string url, IDictionary<string, Object> textParams, IDictionary<string, string> headerParams)
  197. {
  198. HttpWebRequest req = GetWebRequest(url, "POST", headerParams);
  199. req.ContentType = "application/json;charset=utf-8";
  200. String body = TopUtils.ObjectToJson(textParams, new FastJSON.JSONParameters() { UseApiNamingStyle = false, UseExtensions = false, SerializeNullValues = false });
  201. byte[] postData = Encoding.UTF8.GetBytes(body);
  202. System.IO.Stream reqStream = req.GetRequestStream();
  203. reqStream.Write(postData, 0, postData.Length);
  204. reqStream.Close();
  205. HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
  206. Encoding encoding = GetResponseEncoding(rsp);
  207. return GetResponseAsString(rsp, encoding);
  208. }
  209. public HttpWebRequest GetWebRequest(string url, string method, IDictionary<string, string> headerParams)
  210. {
  211. HttpWebRequest req = null;
  212. if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
  213. {
  214. if (this._ignoreSSLCheck)
  215. {
  216. ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(TrustAllValidationCallback);
  217. }
  218. req = (HttpWebRequest)WebRequest.CreateDefault(new Uri(url));
  219. }
  220. else
  221. {
  222. req = (HttpWebRequest)WebRequest.Create(url);
  223. }
  224. if (this._disableWebProxy)
  225. {
  226. req.Proxy = null;
  227. }
  228. if (headerParams != null && headerParams.Count > 0)
  229. {
  230. foreach (string key in headerParams.Keys)
  231. {
  232. req.Headers.Add(key, headerParams[key]);
  233. }
  234. }
  235. req.ServicePoint.Expect100Continue = false;
  236. req.Method = method;
  237. req.KeepAlive = true;
  238. req.UserAgent = "top-sdk-net";
  239. req.Accept = "text/xml,text/javascript";
  240. req.Timeout = this._timeout;
  241. req.ReadWriteTimeout = this._readWriteTimeout;
  242. return req;
  243. }
  244. /// <summary>
  245. /// 把响应流转换为文本。
  246. /// </summary>
  247. /// <param name="rsp">响应流对象</param>
  248. /// <param name="encoding">编码方式</param>
  249. /// <returns>响应文本</returns>
  250. public string GetResponseAsString(HttpWebResponse rsp, Encoding encoding)
  251. {
  252. Stream stream = null;
  253. StreamReader reader = null;
  254. try
  255. {
  256. // 以字符流的方式读取HTTP响应
  257. stream = rsp.GetResponseStream();
  258. if (Constants.CONTENT_ENCODING_GZIP.Equals(rsp.ContentEncoding, StringComparison.OrdinalIgnoreCase))
  259. {
  260. stream = new GZipStream(stream, CompressionMode.Decompress);
  261. }
  262. reader = new StreamReader(stream, encoding);
  263. return reader.ReadToEnd();
  264. }
  265. finally
  266. {
  267. // 释放资源
  268. if (reader != null) reader.Close();
  269. if (stream != null) stream.Close();
  270. if (rsp != null) rsp.Close();
  271. }
  272. }
  273. /// <summary>
  274. /// 组装含参数的请求URL。
  275. /// </summary>
  276. /// <param name="url">请求地址</param>
  277. /// <param name="parameters">请求参数映射</param>
  278. /// <returns>带参数的请求URL</returns>
  279. public static string BuildRequestUrl(string url, IDictionary<string, string> parameters)
  280. {
  281. if (parameters != null && parameters.Count > 0)
  282. {
  283. return BuildRequestUrl(url, BuildQuery(parameters));
  284. }
  285. return url;
  286. }
  287. /// <summary>
  288. /// 组装含参数的请求URL。
  289. /// </summary>
  290. /// <param name="url">请求地址</param>
  291. /// <param name="queries">一个或多个经过URL编码后的请求参数串</param>
  292. /// <returns>带参数的请求URL</returns>
  293. public static string BuildRequestUrl(string url, params string[] queries)
  294. {
  295. if (queries == null || queries.Length == 0)
  296. {
  297. return url;
  298. }
  299. StringBuilder newUrl = new StringBuilder(url);
  300. bool hasQuery = url.Contains("?");
  301. bool hasPrepend = url.EndsWith("?") || url.EndsWith("&");
  302. foreach (string query in queries)
  303. {
  304. if (!string.IsNullOrEmpty(query))
  305. {
  306. if (!hasPrepend)
  307. {
  308. if (hasQuery)
  309. {
  310. newUrl.Append("&");
  311. }
  312. else
  313. {
  314. newUrl.Append("?");
  315. hasQuery = true;
  316. }
  317. }
  318. newUrl.Append(query);
  319. hasPrepend = false;
  320. }
  321. }
  322. return newUrl.ToString();
  323. }
  324. /// <summary>
  325. /// 组装普通文本请求参数。
  326. /// </summary>
  327. /// <param name="parameters">Key-Value形式请求参数字典</param>
  328. /// <returns>URL编码后的请求数据</returns>
  329. public static string BuildQuery(IDictionary<string, string> parameters)
  330. {
  331. if (parameters == null || parameters.Count == 0)
  332. {
  333. return null;
  334. }
  335. StringBuilder query = new StringBuilder();
  336. bool hasParam = false;
  337. foreach (KeyValuePair<string, string> kv in parameters)
  338. {
  339. string name = kv.Key;
  340. string value = kv.Value;
  341. // 忽略参数名或参数值为空的参数
  342. if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
  343. {
  344. if (hasParam)
  345. {
  346. query.Append("&");
  347. }
  348. query.Append(name);
  349. query.Append("=");
  350. query.Append(HttpUtility.UrlEncode(value, Encoding.UTF8));
  351. hasParam = true;
  352. }
  353. }
  354. return query.ToString();
  355. }
  356. private Encoding GetResponseEncoding(HttpWebResponse rsp)
  357. {
  358. string charset = rsp.CharacterSet;
  359. if (string.IsNullOrEmpty(charset))
  360. {
  361. charset = Constants.CHARSET_UTF8;
  362. }
  363. return Encoding.GetEncoding(charset);
  364. }
  365. private static bool TrustAllValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
  366. {
  367. return true; // 忽略SSL证书检查
  368. }
  369. }
  370. }