【原創-算法-實現】異步HTTP請求操做

索引:html

目錄索引json

1、說明數組

  1) 這個類 是我 在真實項目中,優化解決真實問題 時,不參考第三方代碼,徹底由本身查閱MSDN官方文檔 , 完成的一個真實生產環境中使用的功能類閉包

  2) 讀者在使用此類時,請尊重原創,在代碼中加上原創註釋://  Author -- Meng.NET (cnblogs.com)  ,同時歡迎 二次改進、二次創做 以共同進步app

  3) 此代碼以【面向對象】、【C#閉包】、【異步回調】、【超時】、【等待】、【自動重試】方式實現及完成,且能夠配置擴展異步

2、代碼ide

  廢話很少說,上乾貨,代碼以下:優化

  1     /// <summary>
  2     /// 異步 Http
  3     /// </summary>
  4     public class Remoter
  5     {
  6         /*
  7          * LM,2016/08/18
  8          * C#閉包化,異步化,Web操做
  9          * 以便支持POS多接口多操做同時使用
 10          */
 11 
 12         /// <summary>
 13         /// 請求地址
 14         /// </summary>
 15         public string URL { get; set; }
 16 
 17         /// <summary>
 18         /// 請求方式
 19         /// </summary>
 20         public string RequestMethod { get; set; }
 21 
 22         /// <summary>
 23         /// 請求數據
 24         /// </summary>
 25         public string JsonContent { get; set; }
 26 
 27         //
 28         private byte[] Buffer { get; set; }        
 29         private Stream RequestStream { get; set; }        
 30         private HttpWebRequest Request { get; set; }        
 31         private bool ResponseFlag { get; set; }        
 32         private string Result { get; set; }        
 33         private bool TimeoutFlag  { get; set; }        
 34         private int TimeoutTime { get; set; }        
 35         private bool RetryFlag { get; set; }        
 36         private int RetryCount  { get; set; }        
 37         private int WaitSleep { get; set; }        
 38         private int TrySleep { get; set; }
 39 
 40         // 初始化
 41         public Remoter()
 42         {
 43             //
 44             ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
 45             ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) => true);
 46 
 47             // 
 48             this.URL = string.Empty;
 49             this.Request = default(HttpWebRequest);
 50             this.JsonContent = string.Empty;
 51             this.Buffer = default(byte[]);
 52             this.RequestStream = default(Stream);
 53             this.ResponseFlag = false;
 54             this.Result = string.Empty;
 55             this.TimeoutFlag = false;
 56             this.TimeoutTime = 10 * 1000;
 57             this.RetryFlag = false;
 58             this.RetryCount = 3;
 59             this.WaitSleep = 10;
 60             this.RequestMethod = "POST";
 61             this.TrySleep = 2000;
 62         }
 63         
 64         /// <summary>
 65         /// 獲取響應數據
 66         /// </summary>
 67         public string GetRemoteData()
 68         {
 69             //
 70             if(string.IsNullOrWhiteSpace(this.URL))
 71             {
 72                 throw new Exception("HttpAsync.URL,未賦值!");
 73             }
 74 
 75             // 
 76             RemoteNew(SetResult); 
 77 
 78             //
 79             var timeNum = 0;
 80             while (true)
 81             {
 82                 if (ResponseFlag)
 83                 {
 84                     break;
 85                 }
 86                 if (TimeoutFlag)
 87                 {
 88                     throw new Exception(string.Format("請求超時!超時時間:{0}S", TimeoutTime / 1000));
 89                 }
 90                 timeNum += WaitSleep;
 91                 if (timeNum >= TimeoutTime)
 92                 {
 93                     TimeoutFlag = true;
 94                 }
 95                 Thread.Sleep(WaitSleep);
 96             }
 97 
 98             //
 99             return Result;
100         }
101 
102         // 
103         private void RemoteNew(Action<Remoter, string> action) 
104         {
105             //
106             var reNum = 0;
107             for (var i = 0; i < this.RetryCount; i++)
108             {
109                 try
110                 {
111                     //
112                     var uri = URL;
113 
114                     //
115                     this.Request = WebRequest.Create(uri) as HttpWebRequest;
116                     this.Request.KeepAlive = false;
117                     this.Request.Method = this.RequestMethod;
118                     this.Request.Credentials = CredentialCache.DefaultCredentials;
119                     if (this.RequestMethod.Equals("POST", StringComparison.OrdinalIgnoreCase))
120                     {
121                         this.Buffer = Encoding.UTF8.GetBytes(this.JsonContent);
122                         this.Request.ContentLength = this.Buffer.Length;
123                         this.Request.ContentType = "application/json";
124                         this.RequestStream = this.Request.GetRequestStream();
125                         this.RequestStream.Write(this.Buffer, 0, this.Buffer.Length);
126                         this.RequestStream.Close();
127                     }
128 
129                     //
130                     this.Request.BeginGetResponse((arr) =>
131                     {
132                         //
133                         var state = arr.AsyncState as Remoter;
134                         //
135                         var response = state.Request.EndGetResponse(arr) as HttpWebResponse;
136                         var respStream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8"));
137                         action(state, respStream.ReadToEnd());
138                         respStream.Close();
139                         response.Close();
140                     }, this);
141                     //
142                     break;
143                 }
144                 catch (Exception ex)
145                 {
146                     Thread.Sleep(this.TrySleep);
147                     reNum++;
148                     if (reNum == this.RetryCount)
149                     {
150                         throw new Exception(string.Format("重試失敗!重試次數:{0}次,失敗緣由:{1}", this.RetryCount, ex.Message));
151                     }
152                     continue;
153                 }
154             }
155         }        
156         private void SetResult(Remoter state, string jsonData)
157         {
158             if (!string.IsNullOrWhiteSpace(jsonData))
159             {
160                 state.Result = jsonData;
161                 state.ResponseFlag = true;
162             }
163         }
164     }
Remoter.cs

  使用方式:this

  GET: spa

1 var remoter = new Remoter();
2 remoter.RequestMethod = "GET";
3 remoter.URL = "這裏是你要請求的URL";
4 var response = remoter.GetRemoteData();
View Code

  POST:

1 var remoter = new Remoter();
2 remoter.RequestMethod = "POST";
3 remoter.URL = "你要請求的URL";
4 remoter.JsonContent = "你要想URL發送的JSON數據";
5 var response = remoter.GetRemoteData();
View Code

3、代碼解析

    public Remoter() 初始化本類,可配置到 App.config/Web.config 中

 1             // 
 2             this.URL = string.Empty;
 3             this.Request = default(HttpWebRequest);
 4             this.JsonContent = string.Empty;
 5             this.Buffer = default(byte[]);
 6             this.RequestStream = default(Stream);
 7             this.ResponseFlag = false;
 8             this.Result = string.Empty;
 9             this.TimeoutFlag = false;
10             this.TimeoutTime = 10 * 1000;
11             this.RetryFlag = false;
12             this.RetryCount = 3;
13             this.WaitSleep = 10;
14             this.RequestMethod = "POST";
15             this.TrySleep = 2000;
可從配置文件讀取部分

  public string URL 要請求的地址

  public string RequestMethod HTTP 動詞

  public string JsonContent POST 請求時,發送的json數據

  private byte[] Buffer 設置請求流的byte數組

  private Stream RequestStream 請求流

  private HttpWebRequest Request HTTP請求對象

  private bool ResponseFlag 與請求對應的響應是否成功標識

  private string Result 回調狀態保持對象,保存響應結果用

  private bool TimeoutFlag 總超時時間是否超時標識

  private int TimeoutTime 總超時時間(包含若干次重試),默認10s

  private int RetryCount 總URL調用(失敗)自動重試次數,默認3次

  private int WaitSleep 主線程,仿Ajax回調等待時間,默認10ms

  private int TrySleep 每次請求地址失敗後,重試時間間隔,默認2s

  public string GetRemoteData()  解析:

 1             //
 2             var timeNum = 0;
 3             while (true)
 4             {
 5                 if (ResponseFlag)
 6                 {
 7                     break;
 8                 }
 9                 if (TimeoutFlag)
10                 {
11                     throw new Exception(string.Format("請求超時!超時時間:{0}S", TimeoutTime / 1000));
12                 }
13                 timeNum += WaitSleep;
14                 if (timeNum >= TimeoutTime)
15                 {
16                     TimeoutFlag = true;
17                 }
18                 Thread.Sleep(WaitSleep);
19             }
主線程,仿Ajax回調等待

  private void RemoteNew(Action<Remoter, string> action) 解析:

 1         private void RemoteNew(Action<Remoter, string> action) 
 2         {
 3             //
 4             var reNum = 0;
 5             for (var i = 0; i < this.RetryCount; i++)
 6             {
 7                 try
 8                 {
 9                     // 此處省略
10                     //... ...
11 
12                     //
13                     break;
14                 }
15                 catch (Exception ex)
16                 {
17                     Thread.Sleep(this.TrySleep);
18                     reNum++;
19                     if (reNum == this.RetryCount)
20                     {
21                         throw new Exception(string.Format("重試失敗!重試次數:{0}次,失敗緣由:{1}", this.RetryCount, ex.Message));
22                     }
23                     continue;
24                 }
25             }
26         }                        
調用URL失敗,自動重試機制
 1                     //
 2                     this.Request.BeginGetResponse((arr) =>
 3                     {
 4                         //
 5                         var state = arr.AsyncState as Remoter;
 6                         //
 7                         var response = state.Request.EndGetResponse(arr) as HttpWebResponse;
 8                         var respStream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8"));
 9                         action(state, respStream.ReadToEnd());
10                         respStream.Close();
11                         response.Close();
12                     }, this);
異步響應回調,閉包與自狀態保持

   private void SetResult(Remoter state, string jsonData) 解析:

1                 state.Result = jsonData;
2                 state.ResponseFlag = true;
異步響應成功後,在狀態保持中賦值結果

4、計劃中的開源項目...

    計劃後續會將生產中解決問題的諸多地方聚集成一個項目【Meng.Net.dll】並開源至GitHub上,歡迎交流,共同提升~~

  至於本文所講的類會在哪一個命名空間中,還沒想好,項目的總體結構及主打方向,敬請期待......

 

                                         蒙

                                    2016-09-24  22:37  週六

相關文章
相關標籤/搜索