工作中长期需要用到通过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. ASP.NET Hashtable输出JSON格式数据

    最近在开发Windows8 Metro App,使用JavaScript和HTML开发环境.所以操作数据绑定都是使用JSON格式数据.后台使用的是ASP.NET,因为项目相对较小,所有后台没有使用数据 ...

  2. NameNode的ZKFC机制

    转自: http://hackershell.cn/?p=821 NameNode的HA可以个人认为简单分为共享editLog机制和ZKFC对NameNode状态的控制 在此之前,我先提几个问题: 一 ...

  3. MongoDB副本集配置系列二:配置MongoDB副本集

    接上一篇博客: http://www.cnblogs.com/xiaoit/p/4479066.html 1:首先创建3台虚拟机作为配置环境 IP1:192.168.91.128 IP2:192.16 ...

  4. 如何去掉browserLinkSignalR

    在使用vs开发时查看源代码可以发现最下面有以下代码,此段代码会一直请求网络,感觉不爽的可以这样去掉: <!-- Visual Studio Browser Link --> <scr ...

  5. PHP 调用ffmpeg

    PHP 调用ffmpeg linux ffmpeg安装,tar文件安装一直出错,一直无语 php-ffmpeg安装, tar文件安装也一直出错,一直无语 最后直接在系统上安装ffmpeg sudo a ...

  6. 转:Ogre源代码浅析——脚本及其解析(一)

    Ogre的许多外部资源数据都有着相应的脚本格式,现例举如下: Material(材质):Ogre使用的是“大材质”的概念.狭义的“材质”概念往往是与“贴图”等概念区分开的,比如在Lambert光照模型 ...

  7. Android 控件进阶修炼-仿360手机卫士波浪球进度控件

    技术:Android+java   概述 像360卫士的波浪球进度的效果,一般最常用的方法就是 画线的方式,先绘sin线或贝塞尔曲线,然后从左到右绘制竖线,然后再裁剪圆区域. 今天我这用图片bitma ...

  8. 2016年排名Top 100的Java类库——在分析了47,251个依赖之后得出的结论(16年文章)

    本文由HollisChuang 翻译自 The Top 100 Java Libraries in 2016 – After Analyzing 47,251 Dependencies . 原作者:H ...

  9. 总结一下关于mysql 5.6 新特性

    一直断断续续的看一些mysql特性,今天总结一下,以下是列表,网址 http://mariadb.org/ (也是类似的特性), http://mysql.com/ 最近在看关于mysql新特性的一些 ...

  10. tableview中头部信息

    //创建tableview中头部的文件#define kPadding 10 #define kIconWidth 100 #define kIconHeight 100 #define kCount ...