修改 Alipay.AopSdk 的HttpWebRequest 为 HttpClient,主要是适配Core环境,原因是 HttpWebRequest 在 Core 环境下的连接池管理是没有的,高并发下IIS会崩溃。这里没有用HttpClientFactory 主要因为要加入这个改动量应该是不小的,只能用静态 HttpClient 先代替。
下面代码有待在生产环境验证,做个笔记吧,之前这块高并发中跌了个大跟头
using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Text; using System.Web; namespace Alipay.AopSdk.Core.Util { /// <summary> /// 网络工具类。 /// </summary> public sealed class WebUtils { /// <summary> /// 请求与响应的超时时间 /// </summary> public int Timeout { get; set; } = 100000; public static HttpClient client = new HttpClient(); /// <summary> /// 执行HTTP POST请求。 /// </summary> /// <param name="url">请求地址</param> /// <param name="parameters">请求参数</param> /// <param name="charset">编码字符集</param> /// <returns>HTTP响应</returns> public string DoPost(string url, IDictionary<string, string> parameters, string charset) { //var req = GetWebRequest(url, "POST"); //req.ContentType = "application/x-www-form-urlencoded;charset=" + charset; var postData = Encoding.GetEncoding(charset).GetBytes(BuildQuery(parameters, charset)); //var reqStream = req.GetRequestStream(); //reqStream.Write(postData, 0, postData.Length); //reqStream.Close(); //var rsp = (HttpWebResponse) req.GetResponse(); //var encoding = Encoding.GetEncoding(rsp.CharacterSet); //return GetResponseAsString(rsp, encoding); var request = new HttpRequestMessage { RequestUri = new Uri(url), Method = HttpMethod.Post, Content = new ByteArrayContent(postData), }; var response = client.SendAsync(request); return response.ToString(); } /// <summary> /// 执行HTTP GET请求。 /// </summary> /// <param name="url">请求地址</param> /// <param name="parameters">请求参数</param> /// <param name="charset">编码字符集</param> /// <returns>HTTP响应</returns> public string DoGet(string url, IDictionary<string, string> parameters, string charset) { if (parameters != null && parameters.Count > 0) if (url.Contains("?")) url = url + "&" + BuildQuery(parameters, charset); else url = url + "?" + BuildQuery(parameters, charset); //var req = GetWebRequest(url, "GET"); //req.ContentType = "application/x-www-form-urlencoded;charset=" + charset; //var rsp = (HttpWebResponse) req.GetResponse(); //var encoding = Encoding.GetEncoding(rsp.CharacterSet); //return GetResponseAsString(rsp, encoding); var request = new HttpRequestMessage { RequestUri = new Uri(url), Method = HttpMethod.Get }; var response = client.SendAsync(request); return response.ToString(); } /// <summary> /// 执行带文件上传的HTTP POST请求。 /// </summary> /// <param name="url">请求地址</param> /// <param name="textParams">请求文本参数</param> /// <param name="fileParams">请求文件参数</param> /// <param name="charset">编码字符集</param> /// <returns>HTTP响应</returns> public string DoPost(string url, IDictionary<string, string> textParams, IDictionary<string, FileItem> fileParams, string charset) { // 如果没有文件参数,则走普通POST请求 if (fileParams == null || fileParams.Count == 0) return DoPost(url, textParams, charset); var boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线 var req = GetWebRequest(url, "POST"); req.ContentType = "multipart/form-data;charset=" + charset + ";boundary=" + boundary; var reqStream = req.GetRequestStream(); var itemBoundaryBytes = Encoding.GetEncoding(charset).GetBytes("/r/n--" + boundary + "/r/n"); var endBoundaryBytes = Encoding.GetEncoding(charset).GetBytes("/r/n--" + boundary + "--/r/n"); // 组装文本请求参数 var textTemplate = "Content-Disposition:form-data;name=/"{0}/"/r/nContent-Type:text/plain/r/n/r/n{1}"; var textEnum = textParams.GetEnumerator(); while (textEnum.MoveNext()) { var textEntry = string.Format(textTemplate, textEnum.Current.Key, textEnum.Current.Value); var itemBytes = Encoding.GetEncoding(charset).GetBytes(textEntry); reqStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length); reqStream.Write(itemBytes, 0, itemBytes.Length); } // 组装文件请求参数 var fileTemplate = "Content-Disposition:form-data;name=/"{0}/";filename=/"{1}/"/r/nContent-Type:{2}/r/n/r/n"; var fileEnum = fileParams.GetEnumerator(); while (fileEnum.MoveNext()) { var key = fileEnum.Current.Key; var fileItem = fileEnum.Current.Value; var fileEntry = string.Format(fileTemplate, key, fileItem.GetFileName(), fileItem.GetMimeType()); var itemBytes = Encoding.GetEncoding(charset).GetBytes(fileEntry); reqStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length); reqStream.Write(itemBytes, 0, itemBytes.Length); var fileBytes = fileItem.GetContent(); reqStream.Write(fileBytes, 0, fileBytes.Length); } reqStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); reqStream.Close(); var rsp = (HttpWebResponse)req.GetResponse(); var encoding = Encoding.GetEncoding(rsp.CharacterSet); return GetResponseAsString(rsp, encoding); } public HttpWebRequest GetWebRequest(string url, string method) { var req = (HttpWebRequest)WebRequest.Create(url); // req.ServicePoint.Expect100Continue = false; req.Method = method; req.KeepAlive = true; req.UserAgent = "Aop4Net"; req.Timeout = Timeout; return req; } /// <summary> /// 把响应流转换为文本。 /// </summary> /// <param name="rsp">响应流对象</param> /// <param name="encoding">编码方式</param> /// <returns>响应文本</returns> public string GetResponseAsString(HttpWebResponse rsp, Encoding encoding) { var result = new StringBuilder(); Stream stream = null; StreamReader reader = null; try { // 以字符流的方式读取HTTP响应 stream = rsp.GetResponseStream(); reader = new StreamReader(stream, encoding); // 按字符读取并写入字符串缓冲 var ch = -1; while ((ch = reader.Read()) > -1) { // 过滤结束符 var c = (char)ch; if (c != '/0') result.Append(c); } } finally { // 释放资源 if (reader != null) reader.Close(); if (stream != null) stream.Close(); if (rsp != null) rsp.Close(); } return result.ToString(); } /// <summary> /// 组装普通文本请求参数。 /// </summary> /// <param name="parameters">Key-Value形式请求参数字典</param> /// <returns>URL编码后的请求数据</returns> public static string BuildQuery(IDictionary<string, string> parameters, string charset) { var postData = new StringBuilder(); var hasParam = false; var dem = parameters.GetEnumerator(); while (dem.MoveNext()) { var name = dem.Current.Key; var value = dem.Current.Value; // 忽略参数名或参数值为空的参数 if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value)) { if (hasParam) postData.Append("&"); postData.Append(name); postData.Append("="); var encodedValue = HttpUtility.UrlEncode(value, Encoding.GetEncoding(charset)); postData.Append(encodedValue); hasParam = true; } } return postData.ToString(); } } }