关于http异步发送,一开始我的做法都是用thread或者task去完成的;后来发现HttpWebRequest本身就提供一个异步的方法。
总感觉.Net自己提供的异步方法可能要优于我们自己用线程去实现的好;
当然这只是我的猜想。个人感觉如果有大量异步发送还是用HttpWebRequest本身提供的异步方法好。
自己封装了下HttpWebRequest的异步请求。
1 /// <summary> 2 /// http异步请求 3 /// </summary> 4 /// <param name="url">url</param> 5 /// <param name="reqMethod">请求方法 GET、POST</param> 6 /// <param name="callback">回调函数</param> 7 /// <param name="ob">回传对象</param> 8 /// <param name="postData">post数据</param> 9 public static void HttpAsyncRequest(string url, string reqMethod, AsyRequetCallback callback, object ob = null, string postData = "") 10 { 11 Stream requestStream = null; 12 try 13 { 14 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 15 request.ContentType = "application/x-www-form-urlencoded"; 16 request.Method = reqMethod; 17 if (reqMethod.ToUpper() == "POST") 18 { 19 byte[] bytes = Encoding.UTF8.GetBytes(postData); 20 request.ContentLength = bytes.Length; 21 requestStream = request.GetRequestStream(); 22 requestStream.Write(bytes, 0, bytes.Length); 23 } 24 //开始调用异步请求 25 //AsyResultTag 是自定义类 用于传递调用时信息 其中HttpWebRequest 是必须传递对象。 26 //因为回调需要用HttpWebRequest来获取HttpWebResponse 27 request.BeginGetResponse(new AsyncCallback(HttpCallback), new AsyResultTag() { obj = ob, callback = callback, req = request }); 28 } 29 catch (Exception ex) 30 { 31 throw ex; 32 } 33 finally 34 { 35 if (requestStream != null) 36 { 37 requestStream.Close(); 38 } 39 } 40 } 41 42 43 /// <summary> 44 /// http请求回调 由.net内部调用 参数必须为IAsyncResult 45 /// </summary> 46 /// <param name="asynchronousResult">http回调时回传对象</param> 47 private static void HttpCallback(IAsyncResult asynchronousResult) 48 { 49 int statusCode = 0; 50 string retString = ""; 51 AsyResultTag tag = new AsyResultTag(); 52 WebException webEx = null; 53 try 54 { 55 //获取请求时传递的对象 56 tag = asynchronousResult.AsyncState as AsyResultTag; 57 HttpWebRequest req = tag.req; 58 //获取异步返回的http结果 59 HttpWebResponse response = req.EndGetResponse(asynchronousResult) as HttpWebResponse; 60 Stream myResponseStream = response.GetResponseStream(); 61 StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); 62 retString = myStreamReader.ReadToEnd(); 63 myStreamReader.Close(); 64 myResponseStream.Close(); 65 statusCode = ((int)response.StatusCode); 66 67 } 68 catch (WebException ex) 69 { 70 if ((HttpWebResponse)ex.Response != null) 71 { 72 statusCode = ((int)((HttpWebResponse)ex.Response).StatusCode); 73 } 74 75 webEx = ex; 76 } 77 //调用外部回调 即最外层的回调 78 tag.callback(tag.obj, retString, statusCode, webEx); 79 80 } 81 82 /// <summary> 83 /// 异步请求回调委托 84 /// </summary> 85 /// <param name="asyObj">回传对象</param> 86 /// <param name="resStr">http响应结果</param> 87 /// <param name="statusCode">http状态码</param> 88 /// <param name="webEx">异常</param> 89 public delegate void AsyRequetCallback(object asyObj, string respStr, int statusCode, WebException webEx); 90 91 /// <summary> 92 /// 异步返回对象 93 /// </summary> 94 class AsyResultTag 95 { 96 /// <summary> 97 /// 回传对象 98 /// </summary> 99 public object obj { get; set; } 100 /// <summary> 101 /// 当前httpRequest请求实例 102 /// </summary> 103 public HttpWebRequest req { get; set; } 104 /// <summary> 105 /// 回调函数委托 106 /// </summary> 107 public AsyRequetCallback callback { get; set; } 108 }
AsyRequetCallback 异步回调委托,即要回调的函数原型;说下每个参数的意义:
1、object asyObj:回传对象,即请求时附带的一个对象,如果没有可以不用传。比如我们当前的这个请求和用户有所关联,如当前的这个请求对应是某个用户的,请求后我要将结果写到这个用户的某个属性下面;这样我们就可以将此用户信息和当前请求一起携带过去。
2、string respStr:当前http返回结果。
3、int statusCode:http状态码,包括出错时的状态码。如404,403等。
4、WebException webEx 异常信息,异常信息也会随着回调传递到前面来,不直接向上抛或者直接log。好处在于,我们可以针对这个异常信息做单独处理。比如某个用户如果碰到什么403或者404我们应该怎么处理,又或者我们可以将错误信息随着当前用户进行保存,很好的跟踪每个用户的发送情况。