1. 程式人生 > >9102年了,彙總下HttpClient問題,封印一個

9102年了,彙總下HttpClient問題,封印一個

如果找的是core的HttpClientFactory 出門右轉。

  1. 官方寫法,高併發下,TCP連線不能快速釋放,導致端口占完,無法連線

    Dispose 不是馬上關閉tcp連線

    主動關閉的一方為什麼不能馬上close而是進入timewait狀態:TCP四次揮手客戶端關閉連結為什麼要等待2倍MSL

    正確寫法一個域(一個地址) 保證一個靜態httpclient操作,保證重用tcp連線。

     

  2. 如果HttpClient唯一,如果請求頭內容需要變化怎麼辦,異常:"集合已修改;可能無法執行列舉操作"

    HttpClient有個介面SendAsync。看

    原始碼知道其實HttpClient內部get,post,put,delete最終都是呼叫SendAsync。

    這個方法可以允許使用者傳遞HttpRequestMessage,內部包含(HttpRequestHeaders)

     

  3. HttpClient 死鎖

    關於Task同步上下文 造成死鎖問題就不多解釋。避免方法就是ConfigureAwait(false)或者await always。最好是await always。傳送門

    說下不用await 而使用類似HttpClient.GetStringAsync(uri).Result 直接同步獲取為什麼沒有死鎖

    因為HttpClient原始碼裡面用到async await的地方几乎都加了ConfigureAwait(false)。233333

     

  4. 預熱和長連線

    其實這是嘴巴dudu園長大人在很久以前就做分析過 傳送門

     

  5. HttpClient 利用stream和json.net 減少記憶體開銷,加快反序列化過程

    我們一般的請求流程:發起請求,獲取返回的string物件,然後反序列化成我們想要的物件。而其實可以利用stream直接反序列化成我們想要的物件。

    而且可以是在HttpCompletionOption.ResponseHeadersRead的情況下。

    傳送門

     

    HttpClient封印: 

  1     public class HttpAsyncSender
  2     {
  3         private static readonly ILogger Logger = LoggerManager.GetLogger(typeof(HttpAsyncSender));
  4         //靜態 重用tcp連線 長連線(not dispose)https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
  5         private static readonly HttpClient HttpClient = new HttpClient();
  6 
  7         public HttpAsyncSender(Uri baseUri, int timeoutSeconds = 0, bool keepAlive = true, bool preheating = false, long maxResponseContentBufferSize = 0)
  8         {
  9             //基礎地址
 10             HttpClient.BaseAddress = baseUri;
 11             //超時
 12             if (timeoutSeconds != 0)
 13             {
 14                 HttpClient.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
 15             }
 16             //response最大接收位元組 預設2gbmstsc
 17             if (maxResponseContentBufferSize != 0)
 18             {
 19                 HttpClient.MaxResponseContentBufferSize = maxResponseContentBufferSize;
 20             }
 21             //長連線 //https://www.cnblogs.com/lori/p/7692152.html  http 1.1 default set keep alive
 22             if (keepAlive)
 23             {
 24                 HttpClient.DefaultRequestHeaders.Connection.Add("keep-alive");
 25             }
 26             //httpclient 預熱 the first request  //https://www.cnblogs.com/dudu/p/csharp-httpclient-attention.html 
 27             if (preheating)
 28             {
 29                 HttpClient.SendAsync(new HttpRequestMessage
 30                 {
 31                     Method = new HttpMethod("HEAD"),
 32                     RequestUri = new Uri(baseUri + "/")
 33                 }).Result.EnsureSuccessStatusCode();
 34             }
 35         }
 36 
 37         #region 非同步 
 38 
 39         /// <summary>
 40         /// GetAsync 注意 await always
 41         /// </summary>
 42         /// <param name="url"></param>
 43         /// <param name="cancellationToken"></param>
 44         /// <returns></returns>
 45         public async Task<T> GetAsync<T>(string url, CancellationToken cancellationToken)
 46         {
 47             try
 48             {
 49                 //https://johnthiriet.com/efficient-api-calls/ 減少記憶體開銷 利用stream特性 加快反序列化
 50                 using (var request = new HttpRequestMessage(HttpMethod.Get, url))
 51                 {
 52                     var res = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
 53                     var resStesam = await res.Content.ReadAsStreamAsync().ConfigureAwait(false);
 54                     if (res.IsSuccessStatusCode)
 55                     {
 56                         return DeserializeJsonFromStream<T>(resStesam);
 57                     }
 58                     var resStr = await StreamToStringAsync(resStesam).ConfigureAwait(false);
 59                     Logger.Error($"HttpAsyncSender, GetAsync ,response fail StatusCode:{res.StatusCode} resStr:{resStr}  BaseAddress:{HttpClient.BaseAddress},Url:{url}");
 60                 }
 61             }
 62             catch (JsonSerializationException je)
 63             {
 64                 Logger.Error($"HttpAsyncSender,GetAsync JsonSerializationException,BaseAddress:{HttpClient.BaseAddress},Url:{url},je:{je.Message}");
 65                 throw;
 66             }
 67             catch (AggregateException ae)
 68             {
 69                 Logger.Error($"HttpAsyncSender,GetAsync AggregateException,BaseAddress:{HttpClient.BaseAddress},Url:{url} ae:{ae.Flatten()}");
 70                 throw;
 71 
 72             }
 73             catch (Exception e)
 74             {
 75                 Logger.Error($"HttpAsyncSender,GetAsync Exception,BaseAddress:{HttpClient.BaseAddress},Url:{url},ex:{e.Message}");
 76                 throw;
 77             }
 78 
 79             return default(T);
 80         }
 81 
 82         /// <summary>
 83         /// PostAsync 注意 await always
 84         /// </summary>
 85         /// <param name="url"></param>
 86         /// <param name="content"></param>
 87         /// <param name="cancellationToken"></param>
 88         /// <returns></returns>
 89         public async Task<TRes> PostAsync<TReq, TRes>(string url, TReq content, CancellationToken cancellationToken)
 90         {
 91             try
 92             {
 93                 //https://johnthiriet.com/efficient-api-calls/ 減少記憶體開銷 利用stream特性 加快反序列化
 94                 using (var request = new HttpRequestMessage(HttpMethod.Post, url))
 95                 using (var httpContent = CreateHttpContent(content))
 96                 {
 97                     request.Content = httpContent;
 98                     var res = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
 99                     var resStesam = await res.Content.ReadAsStreamAsync().ConfigureAwait(false);
100                     if (res.IsSuccessStatusCode)
101                     {
102                         return DeserializeJsonFromStream<TRes>(resStesam);
103                     }
104                     var resStr = await StreamToStringAsync(resStesam).ConfigureAwait(false);
105                     Logger.Error($"HttpAsyncSender, PostAsync ,response fail StatusCode:{res.StatusCode} resStr:{resStr}  BaseAddress:{HttpClient.BaseAddress},Url:{url}");
106                 }
107             }
108             catch (JsonSerializationException je)
109             {
110                 Logger.Error($"HttpAsyncSender,PostAsync JsonSerializationException,BaseAddress:{HttpClient.BaseAddress},Url:{url},je:{je.Message}");
111                 throw;
112             }
113             catch (AggregateException ae)
114             {
115                 Logger.Error($"HttpAsyncSender,PostAsync AggregateException,BaseAddress:{HttpClient.BaseAddress},Url:{url} ae:{ae.Flatten()}");
116                 throw;
117 
118             }
119             catch (Exception e)
120             {
121                 Logger.Error($"HttpAsyncSender,PostAsync Exception,BaseAddress:{HttpClient.BaseAddress},Url:{url},ex:{e.Message}");
122                 throw;
123             }
124 
125             return default(TRes);
126         }
127 
128         /// <summary>
129         /// SendAsync 注意 await always 當需要動態改變request head的時候 呼叫此方法。 解決 "集合已修改;可能無法執行列舉操作"
130         /// </summary>
131         /// <param name="httpRequestMessage"></param>
132         /// <param name="completionOption"></param>
133         /// <param name="cancellationToken"></param>
134         /// <returns></returns>
135         public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage httpRequestMessage, HttpCompletionOption completionOption, CancellationToken cancellationToken)
136         {
137             try
138             {
139                 return await HttpClient.SendAsync(httpRequestMessage, completionOption, cancellationToken).ConfigureAwait(false);
140             }
141             catch (AggregateException ae)
142             {
143                 Logger.Error(
144                     $"HttpAsyncSender,SendAsync AggregateException,BaseAddress:{HttpClient.BaseAddress},Url:{httpRequestMessage.RequestUri} ae:{ae.Flatten()}");
145                 throw;
146 
147             }
148             catch (Exception e)
149             {
150                 Logger.Error($"HttpAsyncSender,SendAsync Exception,BaseAddress:{HttpClient.BaseAddress},Url:{httpRequestMessage.RequestUri},ex:{e.Message}");
151                 throw;
152             }
153         }
154 
155         #endregion
156 
157 
158         private static T DeserializeJsonFromStream<T>(Stream stream)
159         {
160             if (stream == null || stream.CanRead == false)
161                 return default(T);
162 
163             using (var sr = new StreamReader(stream))
164             using (var jtr = new JsonTextReader(sr))
165             {
166                 var js = new JsonSerializer();
167                 var searchResult = js.Deserialize<T>(jtr);
168                 return searchResult;
169             }
170         }
171 
172         private static async Task<string> StreamToStringAsync(Stream stream)
173         {
174             string content = null;
175 
176             if (stream != null)
177                 using (var sr = new StreamReader(stream))
178                     content = await sr.ReadToEndAsync();
179 
180             return content;
181         }
182 
183         public static void SerializeJsonIntoStream(object value, Stream stream)
184         {
185             using (var sw = new StreamWriter(stream, new UTF8Encoding(false), 1024, true))
186             using (var jtw = new JsonTextWriter(sw) { Formatting = Formatting.None })
187             {
188                 var js = new JsonSerializer();
189                 js.Serialize(jtw, value);
190                 jtw.Flush();
191             }
192         }
193 
194         private static HttpContent CreateHttpContent<T>(T content)
195         {
196             HttpContent httpContent = null;
197             if (content != null)
198             {
199                 var ms = new MemoryStream();
200                 SerializeJsonIntoStream(content, ms);
201                 ms.Seek(0, SeekOrigin.Begin);
202                 httpContent = new StreamContent(ms);
203                 httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
204             }
205 
206             return httpContent;
207         }
208     }
View Code

            HttpWebRequest封印

  1 public class HttpSyncSender
  2     {
  3         private static readonly int DefaultConnectionLimit = 100;
  4         private static readonly ILogger Logger = LoggerManager.GetLogger(typeof(HttpSyncSender));
  5 
  6         static HttpSyncSender()
  7         {
  8             ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;
  9             ServicePointManager.UseNagleAlgorithm = false;
 10             ServicePointManager.MaxServicePointIdleTime = 500 * 1000;
 11         }
 12 
 13         public static void SetDefaultConnectionLimit(int connectionLimit)
 14         {
 15             ServicePointManager.DefaultConnectionLimit = connectionLimit;
 16         }
 17 
 18         #region 同步 HttpWebRequest
 19 
 20         ///  <summary>
 21         ///  同步傳送POST請求  預設表單提交方式
 22         ///  </summary>
 23         ///  <typeparam name="T">T型別</typeparam>
 24         ///  <param name="url">URL</param>
 25         ///  <param name="formData">POST資料</param>
 26         ///  <param name="type">返回值型別:JSON、XML</param>
 27         ///  <param name="timeout">超時時間(單位:毫秒)</param>
 28         /// <param name="headers">請求頭</param>
 29         /// <param name="contentType">內容型別 預設"application/x-www-form-urlencoded"</param>
 30         /// <param name="referer">來源</param>
 31         /// <param name="proxyUrl">代理地址</param>
 32         /// <returns>T型別例項</returns>
 33         public static T HttpPost<T>(string url, EnumRequestType type, NameValueCollection formData, int timeout, NameValueCollection headers, string contentType = "application/x-www-form-urlencoded", string referer = "", string proxyUrl = null) where T : new()
 34         {
 35             T t = default(T);
 36             HttpWebRequest webrequest = null;
 37             var headerStr = headers == null ? string.Empty : JsonConvert.SerializeObject(headers);
 38             try
 39             {
 40                 webrequest = (HttpWebRequest)WebRequest.Create(url);
 41                 webrequest.Method = "POST";
 42                 webrequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB5";
 43                 webrequest.AllowAutoRedirect = true;
 44                 webrequest.Timeout = timeout;
 45                 SetRequest(webrequest, true, proxyUrl);
 46 
 47                 if (headers != null)
 48                 {
 49                     foreach (var item in headers.Keys)
 50                     {
 51                         webrequest.Headers.Add(item.ToString(), Convert.ToString(headers[item.ToString()]));
 52                     }
 53                 }
 54                 byte[] byteArray = Encoding.UTF8.GetBytes(CreateForm(formData));
 55                 webrequest.ContentType = contentType;
 56                 webrequest.ContentLength = byteArray.Length;
 57                 if (!string.IsNullOrWhiteSpace(referer))
 58                 {
 59                     webrequest.Referer = referer;
 60                 }
 61                 using (var dataStream = webrequest.GetRequestStream())
 62                 {
 63                     dataStream.Write(byteArray, 0, byteArray.Length);
 64                 }
 65 
 66                 using (var webResponse = (HttpWebResponse)webrequest.GetResponse())
 67                 {
 68                     using (var resStream = UnzipStream(webResponse))
 69                     {
 70                         var sr = new StreamReader(resStream, Encoding.UTF8);
 71                         var result = sr.ReadToEnd();
 72                         if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result))
 73                         {
 74                             t = CreateInstance<T>(result, type);
 75                         }
 76                         else
 77                         {
 78                             Logger.Error($"HttpSyncSender, Post,返回異常:{webResponse.StatusCode} result:{result} ,Url:{url},cotentType:{contentType} formData:{JsonConvert.SerializeObject(formData)},header:{headerStr}");
 79                         }
 80                         sr.Close();
 81                     }
 82                 }
 83 
 84             }
 85             catch (Exception ex)
 86             {
 87                 Logger.Error($"HttpSyncSender,Post,Url:{url},cotentType:{contentType} formData:{JsonConvert.SerializeObject(formData)},header:{headerStr} ex:{ex.Message}");
 88             }
 89             finally
 90             {
 91                 webrequest?.Abort();
 92             }
 93             return t;
 94         }
 95 
 96         ///  <summary>
 97         ///  同步傳送POST請求 json提交方式
 98         ///  </summary>
 99         ///  <typeparam name="T">T型別</typeparam>
100         /// <param name="url">URL</param>
101         ///  <param name="jsonModel">POST資料</param>
102         ///  <param name="type">返回值型別:JSON、XML</param>
103         ///  <param name="timeout">超時時間(單位:毫秒)</param>
104         /// <param name="headers">請求頭</param>
105         /// <param name="referer">來源</param>
106         /// <param name="proxyUrl">代理地址</param>
107         /// <returns>T型別例項</returns>
108         public static T HttpPost<T>(string url, object jsonModel, EnumRequestType type, int timeout, NameValueCollection headers, string referer = "", string proxyUrl = null) where T : new()
109         {
110             T t = default(T);
111             var headerStr = headers == null ? string.Empty : JsonConvert.SerializeObject(headers);
112             if (jsonModel == null)
113             {
114                 return t;
115             }
116             HttpWebRequest webrequest = null;
117             try
118             {
119                 webrequest = (HttpWebRequest)WebRequest.Create(url);
120                 webrequest.Method = "POST";
121                 webrequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB5";
122                 webrequest.AllowAutoRedirect = true;
123                 webrequest.Timeout = timeout;
124                 SetRequest(webrequest, true, proxyUrl);
125 
126                 if (headers != null)
127                 {
128                     foreach (var item in headers.Keys)
129                     {
130                         webrequest.Headers.Add(item.ToString(), Convert.ToString(headers[item.ToString()]));
131                     }
132                 }
133                 byte[] byteArray = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jsonModel));
134                 webrequest.ContentType = "application/json";
135                 webrequest.ContentLength = byteArray.Length;
136                 if (!string.IsNullOrWhiteSpace(referer))
137                 {
138                     webrequest.Referer = referer;
139                 }
140                 using (Stream dataStream = webrequest.GetRequestStream())
141                 {
142                     dataStream.Write(byteArray, 0, byteArray.Length);
143                 }
144                 using (var webResponse = (HttpWebResponse)webrequest.GetResponse())
145                 {
146                     using (var resStream = UnzipStream(webResponse))
147                     {
148                         var sr = new StreamReader(resStream, System.Text.Encoding.UTF8);
149                         var result = sr.ReadToEnd();
150                         if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result))
151                         {
152                             t = CreateInstance<T>(result, type);
153                         }
154                         else
155                         {
156                             Logger.Error($"HttpSyncSender, Post,返回異常:{webResponse.StatusCode} result:{result} ,Url:{url},cotentType:application/json jsonModel:{JsonConvert.SerializeObject(jsonModel)},header:{headerStr}");
157                         }
158                         sr.Close();
159                     }
160                 }
161 
162             }
163             catch (Exception ex)
164             {
165                 Logger.Error($"HttpSyncSender, Post,Url:{url},cotentType:application/json jsonModel:{JsonConvert.SerializeObject(jsonModel)},header:{headerStr}", ex);
166             }
167             finally
168             {
169                 webrequest?.Abort();
170             }
171             return t;
172         }
173 
174         /// <summary>
175         /// 同步傳送post請求 檔案上傳 multipart
176         /// </summary>
177         /// <typeparam name="T"></typeparam>
178         /// <param name="url"></param>
179         /// <param name="files"></param>
180         /// <param name="type"></param>
181         /// <param name="timeout"></param>
182         /// <param name="formFields"></param>
183         /// <param name="referer"></param>
184         /// <param name="proxyUrl"></param>
185         /// <remarks>https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2</remarks>
186         /// <returns></returns>
187         public static T HttpPost<T>(string url, string[] files, EnumRequestType type, int timeout, NameValueCollection formFields = null, string referer = "", string proxyUrl = null) where T : new()
188         {
189             T t = default(T);
190             HttpWebRequest webrequest = null;
191             if (files == null || files.Length <= 0)
192             {
193                 Logger.Error($"HttpPost,multipart Post,Url:{url},files 地址為空");
194             }
195             var filesStr = JsonConvert.SerializeObject(files);
196             try
197             {
198                 var boundary = $"----------------------------{DateTime.Now.Ticks:x}";
199                 webrequest = (HttpWebRequest)WebRequest.Create(url);
200                 webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
201                 webrequest.Timeout = timeout;
202                 webrequest.Method = "POST";
203 
204                 var memStream = new MemoryStream();
205                 var boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
206                 var endBoundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
207 
208                 if (formFields != null)
209                 {
210                     var formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
211                     foreach (string key in formFields.Keys)
212                     {
213                         var formitem = string.Format(formdataTemplate, key, formFields[key]);
214                         byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
215                         memStream.Write(formitembytes, 0, formitembytes.Length);
216                     }
217                 }
218 
219                 var headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
220 
221                 foreach (var file in files)
222                 {
223                     memStream.Write(boundarybytes, 0, boundarybytes.Length);
224                     var header = string.Format(headerTemplate, "uplTheFile", t);
225                     var headerbytes = Encoding.UTF8.GetBytes(header);
226 
227                     memStream.Write(headerbytes, 0, headerbytes.Length);
228 
229                     using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
230                     {
231                         var buffer = new byte[1024];
232                         int bytesRead;
233                         while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
234                         {
235                             memStream.Write(buffer, 0, bytesRead);
236                         }
237                     }
238                 }
239 
240                 memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
241                 webrequest.ContentLength = memStream.Length;
242 
243                 using (var requestStream = webrequest.GetRequestStream())
244                 {
245                     memStream.Position = 0;
246                     byte[] tempBuffer = new byte[memStream.Length];
247                     memStream.Read(tempBuffer, 0, tempBuffer.Length);
248                     memStream.Close();
249                     requestStream.Write(tempBuffer, 0, tempBuffer.Length);
250                 }
251                 using (var webResponse = (HttpWebResponse)webrequest.GetResponse())
252                 {
253                     using (var resStream = UnzipStream(webResponse))
254                     {
255                         var sr = new StreamReader(resStream, System.Text.Encoding.UTF8);
256                         var result = sr.ReadToEnd();
257                         if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result))
258                         {
259                             t = CreateInstance<T>(result, type);
260                         }
261                         else
262                         {
263                             Logger.Error($"HttpSyncSender,multipart Post,返回異常:{webResponse.StatusCode} result:{result} ,Url:{url},Url:{url},header:{filesStr}");
264                         }
265                         sr.Close();
266                     }
267                 }
268             }
269             catch (Exception ex)
270             {
271                 Logger.Error($"HttpSyncSender,multipart Post,Url:{url},header:{filesStr}", ex);
272             }
273             finally
274             {
275                 webrequest?.Abort();
276             }
277             return t;
278 
279         }
280 
281         /// <summary>
282         /// 同步傳送GET請求
283         /// </summary>
284         /// <typeparam name="T">T型別</typeparam>
285         /// <param name="url">URL</param>
286         /// <param name="type">請求型別</param>
287         /// <param name="parameters">引數</param>
288         /// <param name="timeout">超時時間</param>
289         /// <param name="headers">請求頭</param>
290         /// <param name="callback"></param>
291         /// <param name="proxyUrl">代理地址</param>
292         /// <returns>T型別例項</returns>
293         public static T HttpGet<T>(string url, EnumRequestType type, NameValueCollection parameters, int timeout, NameValueCollection headers, string callback = "", string proxyUrl = null) where T : new()
294         {
295             T t = default(T);
296             HttpWebRequest webrequest = null;
297             var headerStr = headers == null ? string.Empty : JsonConvert.SerializeObject(headers);
298             var parametersStr = parameters == null ? string.Empty : JsonConvert.SerializeObject(parameters);
299             try
300             {
301                 webrequest = (HttpWebRequest)WebRequest.Create(CreateUrl(url, parameters));
302                 webrequest.Method = "GET";
303                 webrequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB5";
304                 webrequest.AllowAutoRedirect = true;
305                 webrequest.Timeout = timeout;
306                 SetRequest(webrequest, false, proxyUrl);
307 
308                 if (headers != null)
309                 {
310                     foreach (var item in headers.Keys)
311                     {
312                         webrequest.Headers.Add(item.ToString(), Convert.ToString(headers[item.ToString()]));
313                     }
314                 }
315                 using (var webResponse = (HttpWebResponse)webrequest.GetResponse())
316                 {
317                     using (Stream resStream = UnzipStream(webResponse))
318                     {
319                         string result;
320                         using (var sr = new StreamReader(resStream, Encoding.UTF8))
321                         {
322                             result = sr.ReadToEnd();
323                         }
324                         if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result))
325                         {
326                             if (!string.IsNullOrEmpty(callback))
327                             {
328                                 result = result.TrimStart((callback + "(").ToCharArray()).TrimEnd(')');
329                             }
330                             t = CreateInstance<T>(result, type);
331                         }
332                         else
333                         {
334 
335                             Logger.Error($"HttpSyncSender, Get,返回異常:{webResponse.StatusCode} result:{result} Url:{url},parameters:{parametersStr},header:{headerStr}");
336                         }
337                     }
338                 }
339 
340             }
341             catch (JsonSerializationException je)
342             {
343                 Logger.Error($"HttpSyncSender,Get JsonSerializationException,Url:{url},parameters:{parametersStr},header:{headerStr},je:{je.Message}");
344                 throw;
345             }
346             catch (Exception ex)
347             {
348                 Logger.Error($"HttpSyncSender, Get,Url:{url},parameters:{parametersStr},header:{headerStr} ex:{ex.Message}");
349                 throw;
350             }
351             finally
352             {
353                 webrequest?.Abort();
354             }
355             return t;
356         }
357 
358         private static void SetRequest(HttpWebRequest httpWebRequest, bool post, string proxyUrl = null)
359         {
360             httpWebRequest.MaximumAutomaticRedirections = 3;
361             httpWebRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
362             httpWebRequest.KeepAlive = true;
363             httpWebRequest.AllowWriteStreamBuffering = false;
364             if (!string.IsNullOrWhiteSpace(proxyUrl))
365             {
366                 httpWebRequest.Proxy = new WebProxy(proxyUrl);
367             }
368             if (post)
369             {
370                 //post 較大資料 先進行一次握手,避免資源浪費
371                 httpWebRequest.ServicePoint.Expect100Continue = false;
372             }
373         }
374 
375         private static Stream UnzipStream(HttpWebResponse httpResponse)
376         {
377             var resStream = httpResponse.GetResponseStream();
378             if (httpResponse.ContentEncoding.ToLower().Contains("gzip"))
379             {
380                 return new GZipStream(resStream, CompressionMode.Decompress);
381             }
382             if (httpResponse.ContentEncoding.ToLower().Contains("deflate"))
383             {
384                 return new DeflateStream(resStream, CompressionMode.Decompress);
385             }
386             return resStream;
387         }
388 
389         private static T CreateInstance<T>(string text, EnumRequestType type) where T : new()
390         {
391             T t = default(T);
392             if (!string.IsNullOrEmpty(text))
393             {
394                 if (type == EnumRequestType.Json)
395                 {
396                     t = JsonConvert.DeserializeObject<T>(text);
397                 }
398                 else
399                 {
400                     using (Stream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(text)))
401                     {
402                         XElement element = XElement.Load(stream);
403                         if (element != null)
404                         {
405                             t = new T();
406                             foreach (var item in t.GetType().GetProperties())
407                             {
408                                 var ele = element.Descendants().SingleOrDefault(c => c.Name.LocalName.ToLower() == item.Name.ToLower());
409                                 if (ele != null && !string.IsNullOrEmpty(ele.Value))
410                                 {
411                                     item.SetValue(t, Convert.ChangeType(ele.Value, item.PropertyType), null);
412                                 }
413                             }
414                         }
415                     }
416                 }
417             }
418             return t;
419         }
420 
421         private static string CreateUrl(string url, NameValueCollection parameters)
422         {
423             string result = string.Empty;
424             if (!string.IsNullOrEmpty(url))
425             {
426                 result = url;
427                 if (parameters != null && parameters.Count > 0)
428                 {
429 
430                     foreach (string key in parameters.Keys)
431                     {
432                         if (result.IndexOf("?") > -1)
433                         {
434                             result += "&" + key + "=" + parameters[key];
435                         }
436                         else
437                         {
438                             result += "?" + key + "=" + parameters[key];
439                         }
440                     }
441                 }
442             }
443             return result;
444         }
445 
446         private static string CreateForm(NameValueCollection parameters)
447         {
448             string _form = string.Empty;
449             if (parameters != null && parameters.Count > 0)
450             {
451                 foreach (string key in parameters.Keys)
452                 {
453                     _form += key + "=" + parameters[key] + "&";
454                 }
455                 _form = _form.TrimEnd('&');
456             }
457             return _form;
458         }
459 
460         #endregion
461     }
View Code