原创-算法-实现异步HTTP请求操作
Posted Meng.NET
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创-算法-实现异步HTTP请求操作相关的知识,希望对你有一定的参考价值。
索引:
一、说明
1) 这个类 是我 在真实项目中,优化解决真实问题 时,不参考第三方代码,完全由自己查阅MSDN官方文档 , 完成的一个真实生产环境中使用的功能类
2) 读者在使用此类时,请尊重原创,在代码中加上原创注释:// Author -- Meng.NET (cnblogs.com) ,同时欢迎 二次改进、二次创作 以共同进步
3) 此代码以【面向对象】、【C#闭包】、【异步回调】、【超时】、【等待】、【自动重试】方式实现及完成,且可以配置扩展
二、代码
废话不多说,上干货,代码如下:
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 }
使用方式:
GET:
1 var remoter = new Remoter(); 2 remoter.RequestMethod = "GET"; 3 remoter.URL = "这里是你要请求的URL"; 4 var response = remoter.GetRemoteData();
POST:
1 var remoter = new Remoter(); 2 remoter.RequestMethod = "POST"; 3 remoter.URL = "你要请求的URL"; 4 remoter.JsonContent = "你要想URL发送的JSON数据"; 5 var response = remoter.GetRemoteData();
三、代码解析
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 }
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 }
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;
四、计划中的开源项目...
计划后续会将生产中解决问题的诸多地方汇集成一个项目【Meng.Net.dll】并开源至GitHub上,欢迎交流,共同提高~~
至于本文所讲的类会在哪个命名空间中,还没想好,项目的整体结构及主打方向,敬请期待......
蒙
2016-09-24 22:37 周六
以上是关于原创-算法-实现异步HTTP请求操作的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot实现http请求的异步长轮询【2】— AsyncHandlerInterceptor方式