工作中长期需要用到通过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. LintCode: Valid Parentheses

    C++ stack<char|int|string>, push(), pop(), top(), empty(), size() class Solution { public: /** ...

  2. 【树莓派】树莓派与XBMC及Kodi、LibreELEC插件(一)

    网上高人多. 高手在民间,饭桶在机关. 越用树莓派,越发现这玩意儿的潜力,我想,未来我们用它,可以做很多事情. 最近在看树莓派的应用场景,看到网上有人用它做电视盒子. 参考相关文章,简单实践了一下,整 ...

  3. 微信小程序 - 沉浸式抽屉(非组件)

    高度有限制,可作为管理界面,点击下载示例:drawer

  4. 微信小程序 - 上传图片组件

    2019-01-08 更新至1.1:修复了一些问题 2019-03-14 全面更新,推荐:https://www.cnblogs.com/cisum/p/10533559.html 使用了es8的as ...

  5. OpenGL 核心技术之立方体贴图

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家.特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  6. 算法笔记_219:泊松分酒(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他 ...

  7. jmap 命令

    1.  jmap -heap pid          查看java 堆(heap)使用情况         using thread-local object allocation.         ...

  8. Error:Failed to resolve: android.arch.core:common:1.1.0

    build. gradle(project)中 allprojects { repositories { jcenter() maven { url 'https://jitpack.io' } ma ...

  9. 在唯一密钥属性“name”设置为“ExtensionlessUrlHandler-Integrated-4.0”时,无法添加类型为“add”的重复集合项

    以管理员运行下面的命令注册: 32位机器: C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i 64位机器: C:\W ...

  10. C#DES加密,JavaDES解密,另转C#和Java实现Des完整代码

    C#DES加密,JavaDES解密,另转C#和Java实现Des完整代码 转载 2014年06月17日 17:36:09 标签: DES / C#DES / JavaDES / C#和Java交叉DE ...