HttpWebRequest、HttpWebResponse、HttpClient、WebClient等http网络访问类的使用示例汇总

工作中长期需要用到通过HTTP调用API以及文件上传下载,积累了不少经验,现在将各种不同方式进行一个汇总。

首先是HttpWebRequest:

 1 /// <summary>
 2 /// 向服务器发送Request
 3 /// </summary>
 4 /// <param name="url">字符串</param>
 5 /// <param name="method">枚举类型的方法Get或者Post</param>
 6 /// <param name="body">Post时必须传值</param>
 7 /// <param name="timeoutSeconds">超时时间,单位秒</param>
 8 /// <returns></returns>
 9 public static string Request(string url, MethodEnum method, string body = "", int timeoutSeconds = 15000)
10 {
11     if (!IsConnectedInternet())
12         return "网络连接错误,请稍后再试。";
13 
14     try
15     {
16         GC.Collect();
17         HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
18         request.Timeout = timeoutSeconds;
19         request.Method = method.ToString();
20         21         //如果是Post的话,则设置body
22         if (method == MethodEnum.POST)
23         {
24             request.ContentType = "application/json";
25             request.KeepAlive = false;
26             byte[] requestBody = Encoding.UTF8.GetBytes(body);
27             request.ContentLength = requestBody.Length;
28 
29             Stream requestStream = request.GetRequestStream();
30             requestStream.Write(requestBody, 0, requestBody.Length);
31         }
32 
33         return Response(request);
34     }
35     catch (Exception ex)
36     {
37         if (ex.InnerException != null)
38             return ex.InnerException.Message;
39         if (ex.Message.Contains("已取消一个任务"))
40             return "连接服务器超时,请重试";
41         if (ex.Message.Contains("404"))
42             return "连接服务器404,请重试";
43         return ex.Message;
44     }
45 }

然后是HttpWebResponse:

 1 /// <summary>
 2 /// 返回Response数据
 3 /// </summary>
 4 /// <param name="request"></param>
 5 /// <returns></returns>
 6 private static string Response(HttpWebRequest request)
 7 {
 8     HttpWebResponse response = (HttpWebResponse)request.GetResponse();
 9 
10     string jsonRead = "";
11 
12     if (response.StatusCode != HttpStatusCode.OK)
13     {
14         return response.StatusCode.ToString();
15     }
16     //接收过程
17     if (response.GetResponseStream() != null)
18     {
19         StreamReader myStreamReader = new StreamReader(response.GetResponseStream() ?? Stream.Null, Encoding.UTF8);
20         jsonRead = myStreamReader.ReadToEnd();
21         myStreamReader.Close();
22     }
23     response.Close();
24     request.Abort();
25 
26     return jsonRead;
27 }

上面两个方法需要配合使用,皆为同步方式。当然也可以将上面两个方法合并到一个方法中,可以参见接下来这个方法。

另外是使用HttpWebRequest和HttpWebResponse进行文件上传,采用异步方式:

 1 public static void UploadFile(string url, string filePath, string fileName, Action<string> callback)
 2 {
 3     // 时间戳,用做boundary
 4     string timeStamp = DateTime.Now.Ticks.ToString("x");
 5 
 6     //根据uri创建HttpWebRequest对象
 7     HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(url));
 8     httpReq.Method = "POST";
 9     httpReq.AllowWriteStreamBuffering = false; //对发送的数据不使用缓存
10     httpReq.Timeout = 300000;  //设置获得响应的超时时间(300秒)
11     httpReq.ContentType = "multipart/form-data; boundary=" + timeStamp;
12 
13     //文件
14     FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
15     BinaryReader binaryReader = new BinaryReader(fileStream);
16 
17     //头信息
18     string boundary = "--" + timeStamp;
19     string dataFormat = boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";filename=\"{1}\"\r\nContent-Type:application/octet-stream\r\n\r\n";
20     string header = string.Format(dataFormat, "file", Path.GetFileName(filePath));
21     byte[] postHeaderBytes = Encoding.UTF8.GetBytes(header);
22 
23     //结束边界
24     byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + timeStamp + "--\r\n");
25 
26     long length = fileStream.Length + postHeaderBytes.Length + boundaryBytes.Length;
27 
28     httpReq.ContentLength = length;//请求内容长度
29 
30     try
31     {
32         //每次上传4k
33         int bufferLength = 4096;
34         byte[] buffer = new byte[bufferLength];
35 
36         //已上传的字节数
37         long offset = 0;
38         int size = binaryReader.Read(buffer, 0, bufferLength);
39         Stream postStream = httpReq.GetRequestStream();
40 
41         //发送请求头部消息
42         postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
43 
44         while (size > 0)
45         {
46             postStream.Write(buffer, 0, size);
47             offset += size;
48             size = binaryReader.Read(buffer, 0, bufferLength);
49         }
50 
51         //添加尾部边界
52         postStream.Write(boundaryBytes, 0, boundaryBytes.Length);
53         postStream.Close();
54 
55         string returnValue = "";
56         //获取服务器端的响应
57         using (HttpWebResponse response = (HttpWebResponse)httpReq.GetResponse())
58         {
59             Stream receiveStream = response.GetResponseStream();
60             StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
61             returnValue = readStream.ReadToEnd();
62             response.Close();
63             readStream.Close();
64         }
65         
66         callback?.Invoke(returnValue);
67     }
68     catch (Exception)
69     {
70         callback?.Invoke("");
71     }
72     finally
73     {
74         fileStream.Close();
75         binaryReader.Close();
76     }
77 }

上面还用到一个enum叫MethodEnum,包含GET和POST两个枚举值。

还有一个比较特殊的POST方法:

 1 public static string HttpPostFormData(string url, Dictionary<string, string> dic)
 2 {
 3     try
 4     {
 5         GC.Collect();
 6         // 时间戳,用做boundary
 7         string timeStamp = DateTime.Now.Ticks.ToString("x");
 8         string boundary = "----" + timeStamp;
 9 
10         HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
11         request.Method = WebRequestMethods.Http.Post;
12         request.ContentType = "multipart/form-data; boundary=" + boundary;
13         request.KeepAlive = true;
14         request.Timeout = 3000;
15 
16         var stream = new MemoryStream();
17 
18         //头信息
19         string dataFormat = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n";
20         foreach (string key in dic.Keys)
21         {
22             string s = string.Format(dataFormat, key, dic[key]);
23             byte[] data = Encoding.UTF8.GetBytes(s);
24             stream.Write(data, 0, data.Length);
25         }
26 
27         //结束边界
28         byte[] boundaryBytes = Encoding.ASCII.GetBytes("--" + boundary + "--");
29         stream.Write(boundaryBytes, 0, boundaryBytes.Length);
30 
31         request.ContentLength = stream.Length;//请求内容长度
32 
33         Stream requestStream = request.GetRequestStream(); //写入请求数据
34         stream.Position = 0L;
35         stream.CopyTo(requestStream);
36         stream.Close();
37 
38         requestStream.Close();
39 
40         return Response(request);
41     }
42     catch (Exception e)
43     {
44         return e.Message;
45     }
46 }

--------------------------------------------------------------------------------------我是分割线-----------------------------------------------------------------------------------------------------------

然后是HttpClient,这个类提供的都是异步方法,下面包含了POST、GET、PUT、DELETE四个方法,还有一个SEND方法稍加改动即可实现:

  1 public static async void AsyncPost(string url, string body, Action<RequestResult> callback, int timeoutSeconds = 10)
  2 {
  3     var requestResult = new RequestResult();
  4     if (!IsConnectedInternet())
  5     {
  6         requestResult.Message = "网络连接错误,请稍后再试。";
  7         callback?.Invoke(requestResult);
  8         return;
  9     }
 10 
 11     try
 12     {
 13         using (var client = new HttpClient())
 14         {
 15             client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6");
 16             client.Timeout = new TimeSpan(0, 0, timeoutSeconds);
 17             //byte[] requestBody = Encoding.UTF8.GetBytes(body);
 18             HttpContent content = new StringContent(body);
 19             content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
 20             var response = await client.PostAsync(url, content);
 21             //确保HTTP成功状态值
 22             response.EnsureSuccessStatusCode();
 23             //await异步读取最后的JSON
 24             await response.Content.ReadAsStringAsync().ContinueWith(t =>
 25             {
 26                 if (t.IsCompleted)
 27                 {
 28                     requestResult.IsSuccess = true;
 29                     requestResult.Result = t.Result;
 30                     callback?.Invoke(requestResult);
 31                 }
 32             });
 33         }
 34     }
 35     catch (Exception e)
 36     {
 37         if (e.InnerException != null)
 38             requestResult.Message = e.InnerException.Message;
 39         else if (e.Message.Contains("已取消一个任务"))
 40             requestResult.Message = "连接服务器超时,请重试";
 41         else if (e.Message.Contains("404"))
 42             requestResult.Message = "连接服务器404,请重试";
 43         else
 44             requestResult.Message = e.Message;
 45         callback?.Invoke(requestResult);
 46     }
 47 }
 48 
 49 public static async void AsyncGet(string url, Action<RequestResult> callback, int timeoutSeconds = 10)
 50 {
 51     var requestResult = new RequestResult();
 52     if (!IsConnectedInternet())
 53     {
 54         requestResult.Message = "网络连接错误,请稍后再试。";
 55         callback?.Invoke(requestResult);
 56         return;
 57     }
 58 
 59     try
 60     {
 61         using (var client = new HttpClient())
 62         {
 63             client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6");
 64             client.Timeout = new TimeSpan(0, 0, timeoutSeconds);
 65             var response = await client.GetAsync(url);
 66             //确保HTTP成功状态值
 67             response.EnsureSuccessStatusCode();
 68             //await异步读取最后的JSON
 69             await response.Content.ReadAsStringAsync().ContinueWith(t =>
 70             {
 71                 if (t.IsCompleted)
 72                 {
 73                     requestResult.IsSuccess = true;
 74                     requestResult.Result = t.Result;
 75                     callback?.Invoke(requestResult);
 76                 }
 77             });
 78         }
 79     }
 80     catch (Exception e)
 81     {
 82         if (e.InnerException != null)
 83             requestResult.Message = e.InnerException.Message;
 84         else if (e.Message.Contains("已取消一个任务"))
 85             requestResult.Message = "连接服务器超时,请重试";
 86         else if (e.Message.Contains("404"))
 87             requestResult.Message = "连接服务器404,请重试";
 88         else
 89             requestResult.Message = e.Message;
 90         callback?.Invoke(requestResult);
 91     }
 92 }
 93 
 94 public static async void AsyncPut(string url, string body, Action<RequestResult> callback, int timeoutSeconds = 10)
 95 {
 96     var requestResult = new RequestResult();
 97     if (!IsConnectedInternet())
 98     {
 99         requestResult.Message = "网络连接错误,请稍后再试。";
100         callback?.Invoke(requestResult);
101         return;
102     }
103 
104     try
105     {
106         using (var client = new HttpClient())
107         {
108             client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6");
109             client.Timeout = new TimeSpan(0, 0, timeoutSeconds);
110             HttpContent content = new StringContent(body);
111             content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
112             var response = await client.PutAsync(url, content);
113             //确保HTTP成功状态值
114             response.EnsureSuccessStatusCode();
115             //await异步读取最后的JSON
116             await response.Content.ReadAsStringAsync().ContinueWith(t =>
117             {
118                 if (t.IsCompleted)
119                 {
120                     requestResult.IsSuccess = true;
121                     requestResult.Result = t.Result;
122                     callback?.Invoke(requestResult);
123                 }
124             });
125         }
126     }
127     catch (Exception e)
128     {
129         if (e.InnerException != null)
130             requestResult.Message = e.InnerException.Message;
131         else if (e.Message.Contains("已取消一个任务"))
132             requestResult.Message = "连接服务器超时,请重试";
133         else if (e.Message.Contains("404"))
134             requestResult.Message = "连接服务器404,请重试";
135         else
136             requestResult.Message = e.Message;
137         callback?.Invoke(requestResult);
138     }
139 }
140 
141 public static async void AsyncDelete(string url, Action<RequestResult> callback, int timeoutSeconds = 10)
142 {
143     var requestResult = new RequestResult();
144     if (!IsConnectedInternet())
145     {
146         requestResult.Message = "网络连接错误,请稍后再试。";
147         callback?.Invoke(requestResult);
148         return;
149     }
150 
151     try
152     {
153         using (var client = new HttpClient())
154         {
155             client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6");
156             client.Timeout = new TimeSpan(0, 0, timeoutSeconds);
157             var response = await client.DeleteAsync(url);
158             //确保HTTP成功状态值
159             response.EnsureSuccessStatusCode();
160             //await异步读取最后的JSON
161             await response.Content.ReadAsStringAsync().ContinueWith(t =>
162             {
163                 if (t.IsCompleted)
164                 {
165                     requestResult.IsSuccess = true;
166                     requestResult.Result = t.Result;
167                     callback?.Invoke(requestResult);
168                 }
169             });
170         }
171     }
172     catch (Exception e)
173     {
174         if (e.InnerException != null)
175             requestResult.Message = e.InnerException.Message;
176         else if (e.Message.Contains("已取消一个任务"))
177             requestResult.Message = "连接服务器超时,请重试";
178         else if (e.Message.Contains("404"))
179             requestResult.Message = "连接服务器404,请重试";
180         else
181             requestResult.Message = e.Message;
182         callback?.Invoke(requestResult);
183     }
184 }

上面使用到的RequestResult类:

 1 public class RequestResult : IDisposable
 2 {
 3     public bool IsSuccess { get; set; }
 4 
 5     public string Result { get; set; }
 6 
 7     public string Message { get; set; }
 8 
 9     public RequestResult(bool isSuccess = false, string result = "", string message = "")
10     {
11         IsSuccess = isSuccess;
12         Result = result;
13         Message = message;
14     }
15 
16     ~RequestResult()
17     {
18         Dispose();
19     }
20 
21     public void Dispose()
22     {
23         Dispose(true);
24         GC.SuppressFinalize(this);//不需要再调用本对象的Finalize方法
25     }
26 
27     protected virtual void Dispose(Boolean disposing)
28     {
29         if (disposing)
30         {
31             //--- 清理托管资源 ---//
32         }
33 
34         //--- 清理非托管资源 ---//
35     }
36 }

还有一个判断Windows系统网络连接状态的方法:

 1 #region 网络状态测试
 2 
 3 [DllImport("winInet.dll")]
 4 private static extern bool InternetGetConnectedState(ref int dwFlag, int dwReserved);
 5 
 6 /// <summary>
 7 /// 用于检查网络是否可以连接互联网,true表示连接成功,false表示连接失败 
 8 /// </summary>
 9 /// <returns></returns>
10 private static bool IsConnectedInternet()
11 {
12     int description = 0;
13     return InternetGetConnectedState(ref description, 0);
14 }
15 
16 #endregion

--------------------------------------------------------------------------------------我是分割线-----------------------------------------------------------------------------------------------------------

最后是使用WebClient进行文件下载,这里使用了Task异步方式,也可以改为普通方法或静态方法:

 1 /// <summary>
 2 /// 下载文件
 3 /// </summary>
 4 /// <param name="fileUrl">文件地址</param>
 5 /// <param name="filePath">文件的本地路径</param>
 6 /// <returns>文件在本地的存储路径</returns>
 7 private Task GetFileLocalPath(string fileUrl, string filePath)
 8 {
 9     return Task.Run(() =>
10     {
11         try
12         {
13             using (var mc = new WebClient())
14             {
15                 mc.DownloadFile(new Uri(fileUrl), filePath);
16             }
17         }
18         catch (Exception ex)
19         {
20             LogHelper.WriteErrorLog("下载文件时出现异常。", ex);
21         }
22     });
23 }
24 
25 /// <summary>
26 /// 下载文件
27 /// </summary>
28 /// <param name="fileUrl">文件地址</param>
29 /// <param name="filePath">文件的本地路径</param>
30 /// <returns>文件在本地的存储路径</returns>
31 private Task DownloadFile(string fileUrl, string filePath)
32 {
33     return Task.Run(() =>
34     {
35         try
36         {
37             using (var webClient = new WebClient())
38             {
39                 var netStream = webClient.OpenRead(fileUrl);
40                 if (netStream != null)
41                 {
42                     FileStream fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
43                     byte[] readbyte = new byte[102400];
44                     int realReadLen = netStream.Read(readbyte, 0, readbyte.Length);
45                     while (realReadLen > 0)
46                     {
47                         fstr.Write(readbyte, 0, realReadLen);
48                         realReadLen = netStream.Read(readbyte, 0, readbyte.Length);
49                         Thread.Sleep(10);
50                     }
51                     netStream.Dispose();
52                     fstr.Flush();
53                     fstr.Close();
54                 }
55             }
56         }
57         catch (Exception ex)
58         {
59             LogHelper.WriteErrorLog("下载文件时出现异常。", ex);
60         }
61     });
62 }

以上,有需要的可以拿去使用,通用性还是能保证的,有特殊用途改改就可以了,比如微信公众平台上传文件时form-data内的name是media。

猜你喜欢

转载自www.cnblogs.com/lionwang/p/9400823.html