HttpWebRequest
这是.NET创建者最初开发用于使用HTTP请求的标准类。
使用HttpWebRequest可以让开发者控制请求/响应流程的各个方面,如 timeouts, cookies, headers, protocols。
另一个好处是HttpWebRequest类不会阻塞UI线程。例如,当您从响应很慢的API服务器下载大文件时,您的应用程序的UI不会停止响应。
HttpWebRequest通常和WebResponse一起使用,一个发送请求,一个获取数据。
HttpWebRquest更为底层一些,能够对整个访问过程有个直观的认识,但同时也更加复杂一些。以GET请求为例,至少需要五行代码才能够实现。
代码语言:javascript复制HttpWebRequest http = (HttpWebRequest)WebRequest.Create("http://example.com");
WebResponse response = http.GetResponse();
Stream stream = response.GetResponseStream();
using (var streamtemn = File.Create("路径"))
{
stream.CopyTo(streamtemn);
}
请求工具类
代码语言:javascript复制using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Text;
namespace SchoolClient.Utils
{
internal class ZHttpUtil
{
/// <summary>
/// Get http请求
/// </summary>
/// <param name="url">
/// 请求地址
/// </param>
/// <param name="timeout">
/// 超时时间
/// </param>
/// <param name="encode">
/// 编码
/// </param>
/// <returns>
/// 返回单个实体
/// </returns>
public static T GetSingle<T>(string url, int timeout = 5000, string encode = "UTF-8") where T : class
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode))
{
try
{
string respStr = GetRespStr(url, timeout, encode);
return ZJsonHelper.JsonToObj<T>(respStr);
}
catch (Exception)
{
}
}
return default(T);
}
/// <summary>
/// Post Http请求
/// </summary>
/// <param name="url">
/// 请求地址
/// </param>
/// <param name="postData">
/// 传输数据
/// </param>
/// <param name="timeout">
/// 超时时间
/// </param>
/// <param name="contentType">
/// 媒体格式
/// </param>
/// <param name="encode">
/// 编码
/// </param>
/// <returns>
/// 泛型集合
/// </returns>
public static List<T> PostAndRespList<T>(string url, string postData, int timeout = 5000, string contentType = "application/json;", string encode = "UTF-8")
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
{
try
{
string respstr = GetStreamReader(url, timeout, encode, postData, contentType);
return ZJsonHelper.JsonToList<T>(respstr);
}
catch (Exception)
{
}
}
return null;
}
/// <summary>
/// Post Http请求
/// </summary>
/// <param name="url">
/// 请求地址
/// </param>
/// <param name="postData">
/// 传输数据
/// </param>
/// <param name="timeout">
/// 超时时间
/// </param>
/// <param name="contentType">
/// 媒体格式
/// </param>
/// <param name="encode">
/// 编码
/// </param>
/// <returns>
/// 泛型集合
/// </returns>
public static T PostAndRespSignle<T>(string url, int timeout = 30000, string postData = "", string contentType = "application/json;", string encode = "UTF-8") where T : class
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
{
try
{
string respstr = GetStreamReader(url, timeout, encode, postData, contentType);
return ZJsonHelper.JsonToObj<T>(respstr);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
LogHelper.WriteErrLog("【登录请求】(PostAndRespSignle)登录失败," ex.Message, ex);
}
}
return default(T);
}
/// <summary>
/// Post Http请求
/// </summary>
/// <param name="url">
/// </param>
/// <param name="postData">
/// </param>
/// <param name="timeout">
/// </param>
/// <param name="contentType">
/// </param>
/// <param name="encode">
/// </param>
/// <returns>
/// 响应流字符串
/// </returns>
public static string PostAndRespStr(string url, string postData = "", int timeout = 5000, string contentType = "application/json;", string encode = "UTF-8")
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
{
try
{
return GetStreamReader(url, timeout, encode, postData, contentType);
}
catch (Exception)
{
}
}
return null;
}
public static string UploadFile(string url, string filePath, string paramName, NameValueCollection nvc)
{
string contentType = filePath.Substring(filePath.LastIndexOf(".") 1);
string filename = filePath.Substring(filePath.LastIndexOf("\") 1);
string boundary = "-----" DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = Encoding.ASCII.GetBytes("rn--" boundary "rn");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.ContentType = "multipart/form-data; boundary=" boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = CredentialCache.DefaultCredentials;
WebResponse wresp = null;
try
{
Stream rs = wr.GetRequestStream();
const string formdataTemplate = "Content-Disposition: form-data; name="{0}"rnrn{1}";
foreach (string key in nvc.Keys)
{
rs.Write(boundarybytes, 0, boundarybytes.Length);
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
rs.Write(formitembytes, 0, formitembytes.Length);
}
rs.Write(boundarybytes, 0, boundarybytes.Length);
const string headerTemplate = "Content-Disposition: form-data; name="{0}"; filename="{1}"rnContent-Type: {2}rnrn";
string header = string.Format(headerTemplate, paramName, filename, contentType);
byte[] headerbytes = Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
rs.Write(buffer, 0, bytesRead);
}
fileStream.Close();
byte[] trailer = Encoding.ASCII.GetBytes("rn--" boundary "--rn");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
string xmlDoc = reader2.ReadToEnd();
return xmlDoc;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
if (wresp != null)
{
wresp.Close();
}
return null;
}
}
private static string GetStreamReader(string url, int timeout, string encode, string postData, string contentType)
{
Stream requestStream = null;
Stream responseStream = null;
StreamReader streamReader = null;
try
{
string AESpostData = postData;
bool IsParameterEncryption = FileToolsCommon.GetConfigValue("IsParameterEncryption") != "0";
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
if (IsParameterEncryption)
{
AESpostData = AESHelper.AESEncrypt(postData, "XINGHUOLIAOYUAN7");
webRequest.Headers.Add("st", "true");
}
byte[] data = Encoding.GetEncoding(encode).GetBytes(AESpostData);
webRequest.Method = "POST";
webRequest.ContentType = contentType ";" encode;
webRequest.ContentLength = data.Length;
webRequest.Timeout = timeout;
webRequest.MaximumAutomaticRedirections = 1;//请求最大次数
requestStream = webRequest.GetRequestStream();
requestStream.Write(data, 0, data.Length);
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
responseStream = webResponse.GetResponseStream();
if (responseStream == null) { return ""; }
streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encode));
return streamReader.ReadToEnd();
}
catch (Exception ex)
{
LogHelper.WriteErrLog("【http请求】(GetStreamReader)请求失败," ex.Message, ex);
return null;
}
finally
{
if (streamReader != null)
{
streamReader.Dispose();
}
if (responseStream != null)
{
responseStream.Dispose();
}
if (requestStream != null)
{
requestStream.Dispose();
}
}
}
/// <summary>
/// Get http请求
/// </summary>
/// <param name="url">
/// </param>
/// <param name="timeout">
/// </param>
/// <param name="encode">
/// </param>
/// <returns>
/// 响应流字符串
/// </returns>
public static string GetResponseString(string url, int timeout = 5000, string encode = "UTF-8")
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode))
{
try
{
return GetRespStr(url, timeout, encode);
}
catch (Exception)
{
}
}
return null;
}
private static string GetRespStr(string url, int timeout, string encode)
{
Stream responseStream = null;
StreamReader streamReader = null;
try
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "GET";
webRequest.Timeout = timeout;
WebResponse webResponse = webRequest.GetResponse();
responseStream = webResponse.GetResponseStream();
if (responseStream == null) { return ""; }
streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encode));
return streamReader.ReadToEnd();
}
catch (Exception)
{
return "";
}
finally
{
if (streamReader != null)
{
streamReader.Dispose();
}
if (responseStream != null)
{
responseStream.Dispose();
}
}
}
}
}
文件下载带进度
代码语言:javascript复制using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Threading;
namespace SchoolClient.Utils
{
internal class ZJDownloadUtil
{
public static void downloadFile(string url, string savepath)
{
string path = savepath;
string filename = url.Substring(url.LastIndexOf("/") 1);
if (!url.StartsWith("http") || filename == null || filename == "")
{
return;
}
path = filename;
// 设置参数
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
//发送请求并获取相应回应数据
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才开始向目标网页发送Post请求
Stream responseStream = response.GetResponseStream();
//创建本地文件写入流
Stream stream = new FileStream(path, FileMode.Create);
byte[] bArr = new byte[1024];
int size = responseStream.Read(bArr, 0, bArr.Length);
while (size > 0)
{
stream.Write(bArr, 0, size);
size = responseStream.Read(bArr, 0, bArr.Length);
}
stream.Close();
responseStream.Close();
}
/// <summary>
/// Http下载文件
/// </summary>
public static Thread downloadFileWithCallback(
string url,
int tag,
string savepath,
Dispatcher dispatcher,
ZJDownloadCallback callback
)
{
string path = savepath;
string filename = url.Substring(url.LastIndexOf("/") 1);
path = filename;
if (!url.StartsWith("http") || filename == null || filename == "")
{
return null;
}
Thread thread = new Thread(
o =>
{
FileInfo fi = new FileInfo(path);
if (fi.Exists)
{
dispatcher.Invoke(
new Action(
() =>
{
callback.downloadEnd(tag, path);
}));
}
else
{
string temppath = path ".tmp";
if (File.Exists(temppath))
{
temppath = "1";
while (File.Exists(temppath))
{
temppath = "1";
if (!File.Exists(temppath))
{
break;
}
}
}
dispatcher.Invoke(
new Action(
() =>
{
callback.downloadBegin(tag);
}));
try
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
Stream responseStream = response.GetResponseStream();
//创建本地文件写入流
Stream stream = new FileStream(temppath, FileMode.Create);
long totalSize = response.ContentLength;
byte[] bArr = new byte[1024];
int size = responseStream.Read(bArr, 0, bArr.Length);
long readsize = 0;
while (size > 0)
{
readsize = size;
stream.Write(bArr, 0, size);
size = responseStream.Read(bArr, 0, bArr.Length);
dispatcher.Invoke(
new Action(
() =>
{
callback.downloadProgress(tag, (int)(readsize * 100 / totalSize));
}));
}
stream.Close();
responseStream.Close();
FileInfo fitemp = new FileInfo(temppath);
fitemp.MoveTo(path);
dispatcher.Invoke(
new Action(
() =>
{
callback.downloadEnd(tag, path);
}));
}
catch (Exception ex)
{
dispatcher.Invoke(new Action(
() =>
{
callback.downloadError(tag, ex.Message);
}));
}
}
});
thread.Start();
return thread;
}
public static void downloadFileWithCallback(
string url,
string path,
int tag,
Dispatcher dispatcher,
ZJDownloadCallback callback
)
{
downloadFileWithCallback(url, tag, path, dispatcher, callback);
}
public interface ZJDownloadCallback
{
/// <summary>
/// 下载开始
/// </summary>
/// <param name="tag"></param>
void downloadBegin(int tag);
/// <summary>
/// 下载过程
/// </summary>
/// <param name="tag"></param>
/// <param name="progress"></param>
void downloadProgress(int tag, int progress);
/// <summary>
/// 下载结束
/// </summary>
/// <param name="tag"></param>
/// <param name="filepath"></param>
void downloadEnd(int tag, string filepath);
/// <summary>
/// 下载结束
/// </summary>
/// <param name="tag"></param>
/// <param name="filepath"></param>
void downloadError(int tag, string msg);
}
}
}
这种方法是早期开发者使用的方法,在当前业务中已经很少使用,由于其更加底层,需要处理一些细节,最多可用于框架内部操作。
WebClient
是一种更高级别的抽象,相当于封装了request和response方法
WebClient是一种更高级别的抽象,是HttpWebRequest为了简化最常见任务而创建的,使用过程中你会发现他缺少基本的header,timeoust的设置,不过这些可以通过继承httpwebrequest来实现。
相对来说,WebClient比WebRequest更加简单,它相当于封装了request和response方法,不过需要说明的是,Webclient和WebRequest继承的是不同类,两者在继承上没有任何关系。
使用WebClient可能比HttpWebRequest直接使用更慢(大约几毫秒),但却更为简单,减少了很多细节,代码量也比较少,比如下载文件的代码,只需要两行。
代码语言:javascript复制using (WebClient webClient = new WebClient())
{
webClient.DownloadFile("http://example.com", "路径");
}
WebClient主要面向了WEB网页场景,在模拟Web操作时使用较为方便,但用在RestFul场景下却比较麻烦,这时候就需要HttpClient出马了。
HttpClient(推荐)
HttpClient是.NET4.5
引入的一个HTTP客户端库
目前业务上使用的比较多的是HttpClient,它适合用于多次请求操作,一般设置好默认头部后,可以进行重复多次的请求,基本上用一个实例可以提交任何的HTTP请求。此外,HttpClient提供了异步支持,可以轻松配合async await
实现异步请求。
调用发现没有ReadAsAsync
方法
Install-Package Microsoft.AspNet.WebApi.Client
原因是
这个方法原来是在这个包里的
System.Net.Http.Formatting
,但是它已经废弃了。 我们可以在NuGet中找到Microsoft.AspNet.WebApi.Client
作为替代。
工具类
代码语言:javascript复制using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Handlers;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace SchoolClient.Utils
{
internal class ZHttpAsyncUtil
{
#region GET请求无参数
/// <summary>
/// GET请求无参数--异步方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="action"></param>
/// <returns></returns>
public static async Task<T> GetAsync<T>(string url)
{
using (HttpClient client = new HttpClient())
{
//基地址/域名
//client.BaseAddress = new Uri(BaseUri);
//设定传输格式为json
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
return default(T);
}
}
#endregion GET请求无参数
#region GET请求
/// <summary>
/// GET请求--异步方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="action">方法</param>
/// <param name="param">参数</param>
/// <returns></returns>
public static async Task<T> GetAsync<T>(string url, Dictionary<string, string> param)
{
using (HttpClient client = new HttpClient())
{
//设定传输格式为json
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
//client.DefaultRequestHeaders.Add("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
StringBuilder strUri = new StringBuilder();
//方法
strUri.AppendFormat("{0}?", url);
//参数
if (param.Count > 0)
{
foreach (KeyValuePair<string, string> pair in param)
{
strUri.AppendFormat("{0}={1}&&", pair.Key, pair.Value);
}
strUri.Remove(strUri.Length - 2, 2); //去掉'&&'
}
else
{
strUri.Remove(strUri.Length - 1, 1); //去掉'?'
}
HttpResponseMessage response = await client.GetAsync(strUri.ToString());
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
return default(T);
}
}
#endregion GET请求
#region POST请求
/// <summary>
/// POST请求--异步方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="action">方法</param>
/// <param name="param">参数</param>
/// <returns></returns>
public static async Task<T> PostAsync<T>(string url, object param)
{
using (HttpClient client = new HttpClient())
{
//基地址/域名
//client.BaseAddress = new Uri(BaseUri);
//设定传输格式为json
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsync(url, param, new JsonMediaTypeFormatter());
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
return default(T);
}
}
#endregion POST请求
#region 文件上传
/// <summary>
/// 文件上传 含参数
/// </summary>
/// <param name="action"></param>
/// <param name="filePaths"></param>
/// <param name="param"></param>
/// <returns></returns>
public static async Task<T> UploadAsync<T>(string url, Dictionary<string, string> filePaths,
Dictionary<string, string> param)
{
using (HttpClient client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
//基地址/域名
//client.BaseAddress = new Uri(BaseUri);
foreach (var filePath in filePaths)
{
var fileContent = new ByteArrayContent(File.ReadAllBytes(filePath.Key));
fileContent.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = filePath.Value
};
content.Add(fileContent);
}
foreach (var pair in param)
{
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(pair.Value));
dataContent.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment") { Name = pair.Key };
content.Add(dataContent);
}
HttpResponseMessage response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
return default(T);
}
}
}
#endregion 文件上传
#region 下载文件
/// <summary>
/// 下载文件
/// </summary>
/// <param name="filePath">要保存到本地的路径全名 如:C://Download/close.png</param>
/// <returns></returns>
public static async Task<bool> DownloadFile(string url, string filePath)
{
try
{
using (var client = new HttpClient())
using (var filestream = new FileStream(filePath, FileMode.Create))
{
var netstream = await client.GetStreamAsync(url);
await netstream.CopyToAsync(filestream);//写入文件
}
return true;
}
catch
{
return false;
}
}
#endregion 下载文件
#region 下载文件 带进度条
/// <summary>
/// 下载网络文件 带进度条 显示当前进度
/// </summary>
/// <param name="filePath">下载完成后的文件名</param>
/// <param name="item">记录</param>
/// <returns></returns>
public static async Task<bool> DownloadFile(
string url,
string filePath,
EventHandler<HttpProgressEventArgs> httpReceiveProgress
)
{
try
{
var progressMessageHandler = new ProgressMessageHandler(new HttpClientHandler());
progressMessageHandler.HttpReceiveProgress = httpReceiveProgress;
using (var client = new HttpClient(progressMessageHandler))
using (var filestream = new FileStream(filePath, FileMode.Create))
{
var netstream = await client.GetStreamAsync(url);
await netstream.CopyToAsync(filestream);//写入文件
}
return true;
}
catch
{
return false;
}
}
#endregion 下载文件 带进度条
}
}
POST请求
代码语言:javascript复制var result = await ZHttpAsyncUtil.PostAsync<ResultVo<AppModel>>(url, new Dictionary<string, string>());
下载带进度
代码语言:javascript复制_ = ZHttpAsyncUtil.DownloadFile(
fileUrl,
ZConfig.tempAppPath "test.exe",
(s, e) =>
{
Console.WriteLine("进度:" e.ProgressPercentage "%");
}
);
区别
HttpWebRequset | WebClient | HttpClient | |
---|---|---|---|
命名空间 | System.Net | System.Net | System.Net.Http |
继承类 | WebRequest | Component | HttpMessageInvoker |
支持url转向 | 是 | 否 | 是 |
支持cookie和session | 是 | 否 | 否 |
支持用户代理服务器 | 是 | 否 | 是 |
使用复杂度 | 高 | 低 | 低 |