工作中长期需要用到通过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. 重设域管理员密码-window server 2008 R2

    How to Reset Your Forgotten Domain Admin Password on Server 2008 R2 Forgetting your password is alwa ...

  2. Jenkins 持续集成综合实战

    Jenkins 是一款流行的开源持续集成(Continuous Integration)工具,广泛用于项目开发,具有自动化构建.测试和部署等功能.本文以 CentOS7 环境为例,总结了 Jenkin ...

  3. selenium安装使用

    pip isntall selenium chromedriver download copy到chrome的安装目录, 并将这个路径加到环境变量的path中 chromedriver与chrome各 ...

  4. Percona-XtraBackup系列三:增量备份恢复

    1:创建测试表和测试库如果需要快速建立测试表和库的话,参考之前写的这篇博客:http://www.cnblogs.com/xiaoit/p/3376685.html create database b ...

  5. 关于Git HEAD^与HEAD~的关系

    关于Git HEAD^与HEAD~的关系 请参考下图,来自stackoverflow http://stackoverflow.com/questions/2221658/whats-the-diff ...

  6. [转发]如何在ASP.NET的web.config配置文件中添加MIME类型

    常常有一些特殊的MIME类型是IIS中没有的,一般来说要我们自己手动添加.如果网站经常更换服务器或者网站代码是提供给多个用户使用,那么会造成网站中用到的特殊的MIME类型要经常性的在IIS上配置.这里 ...

  7. 使用Oracle Data Integrator Studio创建资料档案库

    一.Creating the Database Schema /*第1步:创建临时表空间 */ create temporary tablespace user_temp tempfile 'C:\a ...

  8. jackson 中JsonFormat date类型字段的使用

    为了便于date类型字段的序列化和反序列化,需要在数据结构的date类型的字段上用JsonFormat注解进行注解具体格式如下 @JsonFormat(pattern = "yyyy-MM- ...

  9. Linux开机启动时执行脚本的方法

    方法 1 – 使用 rc.local利用 /etc/ 中的 rc.local 文件在启动时执行脚本与命令.我们在文件中加上一行来执行脚本,这样每次启动系统时,都会执行该脚本.不过我们首先需要为 /et ...

  10. weblogic部署存在中文乱码导致部署失败

    问题描述: weblogic控制台显示错误,是受管节点console日志 <-- 下午10时19分16秒 CST> <Info> <Security> <BE ...