工作中长期需要用到通过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 = )
{
if (!IsConnectedInternet())
return "网络连接错误,请稍后再试。"; try
{
GC.Collect();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = timeoutSeconds;
request.Method = method.ToString();
//如果是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, , 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(""))
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 = ; //设置获得响应的超时时间(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 = ;
byte[] buffer = new byte[bufferLength]; //已上传的字节数
long offset = ;
int size = binaryReader.Read(buffer, , bufferLength);
Stream postStream = httpReq.GetRequestStream(); //发送请求头部消息
postStream.Write(postHeaderBytes, , postHeaderBytes.Length); while (size > )
{
postStream.Write(buffer, , size);
offset += size;
size = binaryReader.Read(buffer, , bufferLength);
} //添加尾部边界
postStream.Write(boundaryBytes, , 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 = ; 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, , data.Length);
} //结束边界
byte[] boundaryBytes = Encoding.ASCII.GetBytes("--" + boundary + "--");
stream.Write(boundaryBytes, , 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 = )
{
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(, , 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(""))
requestResult.Message = "连接服务器404,请重试";
else
requestResult.Message = e.Message;
callback?.Invoke(requestResult);
}
} public static async void AsyncGet(string url, Action<RequestResult> callback, int timeoutSeconds = )
{
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(, , 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(""))
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 = )
{
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(, , 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(""))
requestResult.Message = "连接服务器404,请重试";
else
requestResult.Message = e.Message;
callback?.Invoke(requestResult);
}
} public static async void AsyncDelete(string url, Action<RequestResult> callback, int timeoutSeconds = )
{
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(, , 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(""))
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 = ;
return InternetGetConnectedState(ref description, );
} #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[];
int realReadLen = netStream.Read(readbyte, , readbyte.Length);
while (realReadLen > )
{
fstr.Write(readbyte, , realReadLen);
realReadLen = netStream.Read(readbyte, , readbyte.Length);
Thread.Sleep();
}
netStream.Dispose();
fstr.Flush();
fstr.Close();
}
}
}
catch (Exception ex)
{
LogHelper.WriteErrorLog("下载文件时出现异常。", ex);
}
});
}

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

HttpWebRequest、HttpWebResponse、HttpClient、WebClient等http网络访问类的使用示例汇总的更多相关文章

  1. C#获取网页内容 (WebClient、WebBrowser和HttpWebRequest/HttpWebResponse)

    获取网页数据有很多种方式.在这里主要讲述通过WebClient.WebBrowser和HttpWebRequest/HttpWebResponse三种方式获取网页内容. 这里获取的是包括网页的所有信息 ...

  2. C#网页采集数据的几种方式(WebClient、WebBrowser和HttpWebRequest/HttpWebResponse)

    一.通过WebClient获取网页内容 这是一种很简单的获取方式,当然,其它的获取方法也很简单.在这里首先要说明的是,如果为了实际项目的效率考虑,需要考虑在函数中分配一个内存区域.大概写法如下 //M ...

  3. java网络访问指定出口ip

    java网络访问指定出口ip Table of Contents 1. socket 2. apache httpclient 1 socket 可以在Socket构造函数中指定使用的本地ip,如: ...

  4. 已禁用对分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具启用 DTC 以便在 MSDTC 安全配置中进行网络访问。

    今天写ASP.NET程序,在网页后台的c#代码里写了个事务,事务内部对一张表进行批量插入,对另外一张表进行查询与批量插入. 结果第二张表查询后foreach迭代操作时报错:已禁用对分布式事务管理器(M ...

  5. Android实现网络访问

    Android实现网络访问 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 工程内容 1) 熟练使用HttpURLConnection访问WebServ ...

  6. HttpWebRequest,HttpWebResponse的用法和用途

    1.用途:HettpWebRequest,HettpWebResponse用途和webServers的作用差不多,都是得到一个页面传过来的值.HttpWebRequest 2.用法:--------- ...

  7. WebService只能在本地使用,无法通过网络访问的解决办法

    问题描述:WebService只能在本地使用,无法通过网络访问. 解决方案:在web.config的<system.web></system.web>中间加入如下配置节内容: ...

  8. docker网络-如何让外部网络访问容器资源

    docker网络-如何让外部网络访问容器资源 安装httpd 服务: docker:/root# docker exec -it f63b2633d146 bash bash-4.1# yum ins ...

  9. docker网络访问(三)

    docker网络访问 ifconfig查看网卡,启动docker的时候,docker会帮我们创建一个docker0的网桥. 1.随机映射 docker run -P 2.指定映射 -p hostPor ...

随机推荐

  1. WinForm 之 程序启动不显示主窗体

    在 WinForm 程序启动时,不显示主窗体的实现方法主要有以下5种,第五种最简单,而且效果也不错,第四种方法也值得推荐. 实例代码如下: //隐藏窗体的方法1/5:不指定任何窗体为主窗体 //注意: ...

  2. phpstudy部署thinkPHP

    利用phpstudy配置虚拟主机 Listen 8080 <VirtualHost _default_:80> DocumentRoot "D:\phpStudy\WWW&quo ...

  3. 微信小程序尝鲜一个月现状分析

    概述 曾记得在微信小程序还没有上线的时候,大家都是翘首以待.希望在张小龙,在企鹅的带领下,走出差别于原生开发的还有一条移动开发的道路,我也是一直关注着.知道1月9号,微信小程序最终对外开放了,作为第一 ...

  4. 手把手教你从零实现Linux misc设备驱动一(基于友善之臂4412开发板)

    关于怎样来写一个misc设备,在前面有篇文章已经介绍了大致的流程,如今就让我们来实现一个最简单的misc设备驱动. http://blog.csdn.net/morixinguan/article/d ...

  5. Aerospike系列:5:安装AMC

    1:需要安装的包,如果缺少,请安装. python (2.6+) gcc python-devel 安装相应的模块 sudo pip install markupsafe sudo pip insta ...

  6. 比较typeof与instanceof?

    相同点:JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的. typeof的定义和用法:返回值是一个字符串,用来说明变量的数据类型. 细节: ...

  7. Spring Boot 之 RESTfull API简单项目的快速搭建(二)

    1.打包 -- Maven build 2.问题 [WARNING] The requested profile "pom.xml" could not be activated ...

  8. js自动补全空白列(即缺少td的列)

    //自动补全空白列 var rows = document.getElementById("gridTable").rows; //行对象 var allcells = rows[ ...

  9. 〖Linux〗使用命令行切换触摸板的状态on/off/toggle

    最近发现在Ubuntu13.10中使用Fn+F9对触摸板的控制操作不灵了: 并且在黑夜.外置键盘时,按下这个组合键也很不方便,由此便想到使用命令行来切换触摸板状态: 脚本:~/bin/touchpad ...

  10. 【DB2】表空间相关详细说明

    -.创建表空间 1.创建用户表空间 声明:在指定表空间创建路径的时候,需要指定空文件夹,非空文件夹会导致创建报错!!!如果文件夹不存在,那么在创建表空间的时候会自动创建文件夹! 1.1 创建SMS表空 ...