HttpWebRequest、HttpWebResponse、HttpClient、WebClient等http网络访问类的使用示例汇总
工作中长期需要用到通过HTTP调用API以及文件上传下载,积累了不少经验,现在将各种不同方式进行一个汇总。
首先是HttpWebRequest:
/// <summary> /// 向服务器发送Request /// </summary> /// <param name="url">字符串</param> /// <param name="method">枚举类型的方法Get或者Post</param> /// <param name="body">Post时必须传值</param> /// <param name="timeoutSeconds">超时时间,单位秒</param> /// <returns></returns> public static string Request(string url, MethodEnum method, string body = "", int timeoutSeconds = 15000) { if (!IsConnectedInternet()) return "网络连接错误,请稍后再试。"; try { GC.Collect(); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Timeout = timeoutSeconds; request.Method = method.ToString(); 21 //如果是Post的话,则设置body if (method == MethodEnum.POST) { request.ContentType = "application/json"; request.KeepAlive = false; byte[] requestBody = Encoding.UTF8.GetBytes(body); request.ContentLength = requestBody.Length; Stream requestStream = request.GetRequestStream(); requestStream.Write(requestBody, 0, requestBody.Length); } return Response(request); } catch (Exception ex) { if (ex.InnerException != null) return ex.InnerException.Message; if (ex.Message.Contains("已取消一个任务")) return "连接服务器超时,请重试"; if (ex.Message.Contains("404")) return "连接服务器404,请重试"; return ex.Message; } }
然后是HttpWebResponse:
/// <summary> /// 返回Response数据 /// </summary> /// <param name="request"></param> /// <returns></returns> private static string Response(HttpWebRequest request) { HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string jsonRead = ""; if (response.StatusCode != HttpStatusCode.OK) { return response.StatusCode.ToString(); } //接收过程 if (response.GetResponseStream() != null) { StreamReader myStreamReader = new StreamReader(response.GetResponseStream() ?? Stream.Null, Encoding.UTF8); jsonRead = myStreamReader.ReadToEnd(); myStreamReader.Close(); } response.Close(); request.Abort(); return jsonRead; }
上面两个方法需要配合使用,皆为同步方式。当然也可以将上面两个方法合并到一个方法中,可以参见接下来这个方法。
另外是使用HttpWebRequest和HttpWebResponse进行文件上传,采用同步方法异步回调方式:
public static void UploadFile(string url, string filePath, string fileName, Action<string> callback) { // 时间戳,用做boundary string timeStamp = DateTime.Now.Ticks.ToString("x"); //根据uri创建HttpWebRequest对象 HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(url)); httpReq.Method = "POST"; httpReq.AllowWriteStreamBuffering = false; //对发送的数据不使用缓存 httpReq.Timeout = 300000; //设置获得响应的超时时间(300秒) httpReq.ContentType = "multipart/form-data; boundary=" + timeStamp; //文件 FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); BinaryReader binaryReader = new BinaryReader(fileStream); //头信息 string boundary = "--" + timeStamp; string dataFormat = boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";filename=\"{1}\"\r\nContent-Type:application/octet-stream\r\n\r\n"; string header = string.Format(dataFormat, "file", Path.GetFileName(filePath)); byte[] postHeaderBytes = Encoding.UTF8.GetBytes(header); //结束边界 byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + timeStamp + "--\r\n"); long length = fileStream.Length + postHeaderBytes.Length + boundaryBytes.Length; httpReq.ContentLength = length;//请求内容长度 try { //每次上传4k int bufferLength = 4096; byte[] buffer = new byte[bufferLength]; //已上传的字节数 long offset = 0; int size = binaryReader.Read(buffer, 0, bufferLength); Stream postStream = httpReq.GetRequestStream(); //发送请求头部消息 postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length); while (size > 0) { postStream.Write(buffer, 0, size); offset += size; size = binaryReader.Read(buffer, 0, bufferLength); } //添加尾部边界 postStream.Write(boundaryBytes, 0, boundaryBytes.Length); postStream.Close(); string returnValue = ""; //获取服务器端的响应 using (HttpWebResponse response = (HttpWebResponse)httpReq.GetResponse()) { Stream receiveStream = response.GetResponseStream(); StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8); returnValue = readStream.ReadToEnd(); response.Close(); readStream.Close(); } callback?.Invoke(returnValue); } catch (Exception) { callback?.Invoke(""); } finally { fileStream.Close(); binaryReader.Close(); } }
上面还用到一个enum叫MethodEnum,包含GET和POST两个枚举值。
还有一个比较特殊的POST方法:
public static string HttpPostFormData(string url, Dictionary<string, string> dic) { try { GC.Collect(); // 时间戳,用做boundary string timeStamp = DateTime.Now.Ticks.ToString("x"); string boundary = "----" + timeStamp; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = WebRequestMethods.Http.Post; request.ContentType = "multipart/form-data; boundary=" + boundary; request.KeepAlive = true; request.Timeout = 3000; var stream = new MemoryStream(); //头信息 string dataFormat = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n"; foreach (string key in dic.Keys) { string s = string.Format(dataFormat, key, dic[key]); byte[] data = Encoding.UTF8.GetBytes(s); stream.Write(data, 0, data.Length); } //结束边界 byte[] boundaryBytes = Encoding.ASCII.GetBytes("--" + boundary + "--"); stream.Write(boundaryBytes, 0, boundaryBytes.Length); request.ContentLength = stream.Length;//请求内容长度 Stream requestStream = request.GetRequestStream(); //写入请求数据 stream.Position = 0L; stream.CopyTo(requestStream); stream.Close(); requestStream.Close(); return Response(request); } catch (Exception e) { return e.Message; } }
然后是HttpClient,这个类提供的都是异步方法,下面包含了POST、GET、PUT、DELETE四个方法,还有一个SEND方法稍加改动即可实现:
public static async void AsyncPost(string url, string body, Action<RequestResult> callback, int timeoutSeconds = 10) { var requestResult = new RequestResult(); if (!IsConnectedInternet()) { requestResult.Message = "网络连接错误,请稍后再试。"; callback?.Invoke(requestResult); return; } try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6"); client.Timeout = new TimeSpan(0, 0, timeoutSeconds); //byte[] requestBody = Encoding.UTF8.GetBytes(body); HttpContent content = new StringContent(body); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = await client.PostAsync(url, content); //确保HTTP成功状态值 response.EnsureSuccessStatusCode(); //await异步读取最后的JSON await response.Content.ReadAsStringAsync().ContinueWith(t => { if (t.IsCompleted) { requestResult.IsSuccess = true; requestResult.Result = t.Result; callback?.Invoke(requestResult); } }); } } catch (Exception e) { if (e.InnerException != null) requestResult.Message = e.InnerException.Message; else if (e.Message.Contains("已取消一个任务")) requestResult.Message = "连接服务器超时,请重试"; else if (e.Message.Contains("404")) requestResult.Message = "连接服务器404,请重试"; else requestResult.Message = e.Message; callback?.Invoke(requestResult); } } public static async void AsyncGet(string url, Action<RequestResult> callback, int timeoutSeconds = 10) { var requestResult = new RequestResult(); if (!IsConnectedInternet()) { requestResult.Message = "网络连接错误,请稍后再试。"; callback?.Invoke(requestResult); return; } try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6"); client.Timeout = new TimeSpan(0, 0, timeoutSeconds); var response = await client.GetAsync(url); //确保HTTP成功状态值 response.EnsureSuccessStatusCode(); //await异步读取最后的JSON await response.Content.ReadAsStringAsync().ContinueWith(t => { if (t.IsCompleted) { requestResult.IsSuccess = true; requestResult.Result = t.Result; callback?.Invoke(requestResult); } }); } } catch (Exception e) { if (e.InnerException != null) requestResult.Message = e.InnerException.Message; else if (e.Message.Contains("已取消一个任务")) requestResult.Message = "连接服务器超时,请重试"; else if (e.Message.Contains("404")) requestResult.Message = "连接服务器404,请重试"; else requestResult.Message = e.Message; callback?.Invoke(requestResult); } } public static async void AsyncPut(string url, string body, Action<RequestResult> callback, int timeoutSeconds = 10) { var requestResult = new RequestResult(); if (!IsConnectedInternet()) { requestResult.Message = "网络连接错误,请稍后再试。"; callback?.Invoke(requestResult); return; } try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6"); client.Timeout = new TimeSpan(0, 0, timeoutSeconds); HttpContent content = new StringContent(body); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = await client.PutAsync(url, content); //确保HTTP成功状态值 response.EnsureSuccessStatusCode(); //await异步读取最后的JSON await response.Content.ReadAsStringAsync().ContinueWith(t => { if (t.IsCompleted) { requestResult.IsSuccess = true; requestResult.Result = t.Result; callback?.Invoke(requestResult); } }); } } catch (Exception e) { if (e.InnerException != null) requestResult.Message = e.InnerException.Message; else if (e.Message.Contains("已取消一个任务")) requestResult.Message = "连接服务器超时,请重试"; else if (e.Message.Contains("404")) requestResult.Message = "连接服务器404,请重试"; else requestResult.Message = e.Message; callback?.Invoke(requestResult); } } public static async void AsyncDelete(string url, Action<RequestResult> callback, int timeoutSeconds = 10) { var requestResult = new RequestResult(); if (!IsConnectedInternet()) { requestResult.Message = "网络连接错误,请稍后再试。"; callback?.Invoke(requestResult); return; } try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("authorization", "LJQfL1A2oeP2fuEiOHo6"); client.Timeout = new TimeSpan(0, 0, timeoutSeconds); var response = await client.DeleteAsync(url); //确保HTTP成功状态值 response.EnsureSuccessStatusCode(); //await异步读取最后的JSON await response.Content.ReadAsStringAsync().ContinueWith(t => { if (t.IsCompleted) { requestResult.IsSuccess = true; requestResult.Result = t.Result; callback?.Invoke(requestResult); } }); } } catch (Exception e) { if (e.InnerException != null) requestResult.Message = e.InnerException.Message; else if (e.Message.Contains("已取消一个任务")) requestResult.Message = "连接服务器超时,请重试"; else if (e.Message.Contains("404")) requestResult.Message = "连接服务器404,请重试"; else requestResult.Message = e.Message; callback?.Invoke(requestResult); } }
上面使用到的RequestResult类:
public class RequestResult : IDisposable { public bool IsSuccess { get; set; } public string Result { get; set; } public string Message { get; set; } public RequestResult(bool isSuccess = false, string result = "", string message = "") { IsSuccess = isSuccess; Result = result; Message = message; } ~RequestResult() { Dispose(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this);//不需要再调用本对象的Finalize方法 } protected virtual void Dispose(Boolean disposing) { if (disposing) { //--- 清理托管资源 ---// } //--- 清理非托管资源 ---// } }
还有一个判断Windows系统网络连接状态的方法:
#region 网络状态测试 [DllImport("winInet.dll")] private static extern bool InternetGetConnectedState(ref int dwFlag, int dwReserved); /// <summary> /// 用于检查网络是否可以连接互联网,true表示连接成功,false表示连接失败 /// </summary> /// <returns></returns> private static bool IsConnectedInternet() { int description = 0; return InternetGetConnectedState(ref description, 0); } #endregion
最后是使用WebClient进行文件下载,这里使用了Task异步方式,也可以改为普通方法或静态方法:
/// <summary> /// 下载文件 /// </summary> /// <param name="fileUrl">文件地址</param> /// <param name="filePath">文件的本地路径</param> /// <returns>文件在本地的存储路径</returns> private Task GetFileLocalPath(string fileUrl, string filePath) { return Task.Run(() => { try { using (var mc = new WebClient()) { mc.DownloadFile(new Uri(fileUrl), filePath); } } catch (Exception ex) { LogHelper.WriteErrorLog("下载文件时出现异常。", ex); } }); } /// <summary> /// 下载文件 /// </summary> /// <param name="fileUrl">文件地址</param> /// <param name="filePath">文件的本地路径</param> /// <returns>文件在本地的存储路径</returns> private Task DownloadFile(string fileUrl, string filePath) { return Task.Run(() => { try { using (var webClient = new WebClient()) { var netStream = webClient.OpenRead(fileUrl); if (netStream != null) { FileStream fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write); byte[] readbyte = new byte[102400]; int realReadLen = netStream.Read(readbyte, 0, readbyte.Length); while (realReadLen > 0) { fstr.Write(readbyte, 0, realReadLen); realReadLen = netStream.Read(readbyte, 0, readbyte.Length); Thread.Sleep(10); } netStream.Dispose(); fstr.Flush(); fstr.Close(); } } } catch (Exception ex) { LogHelper.WriteErrorLog("下载文件时出现异常。", ex); } }); }
以上,有需要的可以拿去使用,通用性还是能保证的,有特殊用途改改就可以了,比如微信公众平台上传文件时form-data内的name是media。
分类:
C#
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤