C#网络编程之Http请求
本片篇分享简单介绍C#中的Http请求,前几天帮朋友的项目封装ApiHelper,我粗糙的结果就如下,想想我真的是差的太远了。还有一位架构师也在封装这个Helper , 所以最后的结果当然是使用大牛的封装,这篇分享后,准备学习下他的封装,配置,错误处理机制等思想。不过这次也使我对C#网络编程了解的更多,算是一次学习经历吧。真心喜欢和老司机合作,下一阶段将会持续跟这位朋友学习项目底层的封装,和他谦虚的态度,有这样的机会也是幸运的。
你可以将其封装成自己的HttpHelper,经朋友建议,统一Http请求的入参和出参。在HttpClient方面也参考了dudu的关于httpclient预热的文章。C#中HttpClient使用注意:预热与长连接。
为了做到统一入参和出参,定义了Req<T>泛型类和Resp<T>泛型类。你可以根据自己的需要进行拓展。
1 public class Req<T>
2 {
3 /// <summary>
4 /// 传入数据
5 /// </summary>
6 public T Input { get; set; }
7 /// <summary>
8 /// 请求地址
9 /// </summary>
10 public string Url { get; set; }
11 }
1 public class Resp<T>
2 {
3 /// <summary>
4 /// 错误消息
5 /// </summary>
6 public string ErrorMsg { get; set; }
7 /// <summary>
8 /// 状态码
9 /// </summary>
10 public int StatusCode { get; set; }
11 /// <summary>
12 /// 返回数据
13 /// </summary>
14 public T RespData { get; set; }
15 }
虽然保持了httpClient对象复用,但需要注意的是,在设置了httpClient,并且发生了一次请求之后,不能再对其属性进行重新设置。这也正是我又定义了一个fileClient的理由。
1 #region HttpClient版本
2 private static readonly string _baseAddress = ConfigurationManager.AppSettings["api-server"];//配置BaseUrl eg.http://localhost:1234
3 private static readonly HttpClient _httpClient;
4 private static readonly HttpClient _fileClient;
5
6 static ApiHelper()
7 {
8 #region 初始化和预热 httpClient
9 _httpClient = new HttpClient();
10 _httpClient.BaseAddress = new Uri(_baseAddress);
11 _httpClient.Timeout = TimeSpan.FromMilliseconds(2000);
12 _httpClient.DefaultRequestHeaders.Add("Accept", "application/json");//application/xml 想Accept的数据格式
13
14 _httpClient.SendAsync(new HttpRequestMessage
15 {
16 Method = new HttpMethod("HEAD"),
17 RequestUri = new Uri(_baseAddress + "/api/test/HttpClientHot")
18 })
19 .Result.EnsureSuccessStatusCode();
20 #endregion
21
22 #region 初始化和预热 fileClient
23
24 _fileClient = new HttpClient();
25 _fileClient.BaseAddress = new Uri(_baseAddress + "/api/test/HttpClientHot");
26 _fileClient.MaxResponseContentBufferSize = 256000;
27
28 #endregion
29 }
30
31 /// <summary>
32 /// http Get请求
33 /// </summary>
34 /// <typeparam name="T">入参类型</typeparam>
35 /// <typeparam name="TResult">出参类型</typeparam>
36 /// <param name="req">入参对象</param>
37 /// <returns></returns>
38 public static async Task<Resp<TResult>> GetAsync<T, TResult>(Req<T> req)
39 {
40 try
41 {
42 var result =await _httpClient.GetAsync(req.Url).Result.Content.ReadAsStringAsync();
47 return new Resp<TResult>() { Data = JsonHelper.JsonDeserialize<TResult>(result) };
48 }
49 catch(Exception ex)
50 {
51
52 }
53 return new Resp<TResult>() { Data = JsonHelper.JsonDeserialize<TResult>("") };
54
55 }
56
57 /// <summary>
58 /// http Post请求
59 /// </summary>
60 /// <typeparam name="T">入参类型</typeparam>
61 /// <typeparam name="TResult">出参类型</typeparam>
62 /// <param name="req">入参对象</param>
63 /// <returns></returns>
64 public static async Task<Resp<TResult>> PostAsJsonAsync<T, TResult>(Req<T> req)
65 {
66 var result = await _httpClient.PostAsJsonAsync(req.Url, req.Input).Result.Content.ReadAsStringAsync();
67 return new Resp<TResult>() { Data = JsonHelper.JsonDeserialize<TResult>(result) };
68 }
69
70 /// <summary>
71 /// 上传文件
72 /// </summary>
73 /// <typeparam name="T"></typeparam>
74 /// <typeparam name="TResult"></typeparam>
75 /// <param name="req"></param>
76 /// <param name="filePath"></param>
77 /// <returns></returns>
78 public static async Task<Resp<TResult>> SendFile<T, TResult>(Req<T> req, string filePath)//D:\\white.jpg
79 {
80 //_fileClient.DefaultRequestHeaders.Add("user-agent", "User-Agent Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; MALNJS; rv:11.0) like Gecko");//设置请求头
81 // 读文件流
82 FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
83 HttpContent fileContent = new StreamContent(fs);//为文件流提供的HTTP容器
84 fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");//设置媒体类型
85 MultipartFormDataContent mulContent = new MultipartFormDataContent("----");//创建用于可传递文件的容器
86 string fileName = filePath.Substring(filePath.LastIndexOf("/") + 1);
87 mulContent.Add(fileContent, "form", fileName);//第二个参数是表单名,第三个是文件名。
88 HttpResponseMessage response = await _fileClient.PostAsync(req.Url, mulContent);
89 response.EnsureSuccessStatusCode();
90 string result = await response.Content.ReadAsStringAsync();
91 return new Resp<TResult>() { Data = JsonHelper.JsonDeserialize<TResult>(result) };
92 }
93
94 /// <summary>
95 /// 下载
96 /// </summary>
97 /// <param name="url"></param>
98 /// <returns></returns>
99 public static async Task<Resp<byte[]>> HttpDownloadData<T>(Req<T> req)
100 {
101 var byteres = await _fileClient.GetByteArrayAsync(req.Url);
102 return new Resp<byte[]>() { Data = byteres };
103 }
104
105 #endregion
106 }
另外分享下HttpWebRequest来实现的请求。HttpWebRequest需要你自行设置很多内容,当然这也证明其内容丰富。下面代码包含了post,get,以及上传。
/// <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)
{
// webRequest.Headers.Add("Authorization", "Bearer " + "SportApiAuthData");
HttpWebResponse webResponse = null;
Stream responseStream = null;
Stream requestStream = null;
StreamReader streamReader = null;
try
{
string respstr = GetStreamReader(url, responseStream, requestStream, streamReader, webResponse, timeout, encode, postData, contentType);
return JsonHelper.JsonDeserialize<List<T>>(respstr);
}
catch (Exception ex)
{
}
finally
{
if (responseStream != null) responseStream.Dispose();
if (webResponse != null) webResponse.Dispose();
if (requestStream != null) requestStream.Dispose();
if (streamReader != null) streamReader.Dispose();
}
}
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 = 5000, string postData = "", string contentType = "application/json;", string encode = "UTF-8")
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
{
// webRequest.Headers.Add("Authorization", "Bearer " + "SportApiAuthData");
HttpWebResponse webResponse = null;
Stream responseStream = null;
Stream requestStream = null;
StreamReader streamReader = null;
try
{
string respstr = GetStreamReader(url, responseStream, requestStream, streamReader, webResponse, timeout, encode, postData, contentType);
return JsonHelper.JsonDeserialize<T>(respstr);
}
catch (Exception ex)
{
}
finally
{
if (responseStream != null) responseStream.Dispose();
if (webResponse != null) webResponse.Dispose();
if (requestStream != null) requestStream.Dispose();
if (streamReader != null) streamReader.Dispose();
}
}
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, int timeout = 5000, string postData = "", string contentType = "application/json;", string encode = "UTF-8")
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
{
HttpWebResponse webResponse = null;
Stream responseStream = null;
Stream requestStream = null;
StreamReader streamReader = null;
try
{
return GetStreamReader(url, responseStream, requestStream, streamReader, webResponse, timeout, encode, postData, contentType);
}
catch (Exception ex)
{
}
finally
{
if (responseStream != null) responseStream.Dispose();
if (webResponse != null) webResponse.Dispose();
if (requestStream != null) requestStream.Dispose();
if (streamReader != null) streamReader.Dispose();
}
}
return null;
}
private static string GetStreamReader(string url, Stream responseStream, Stream requestStream, StreamReader streamReader, WebResponse webResponse, int timeout, string encode, string postData, string contentType)
{
byte[] data = Encoding.GetEncoding(encode).GetBytes(postData);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
SetAuth(webRequest);
webRequest.Method = "POST";
webRequest.ContentType = contentType + ";" + encode;
webRequest.ContentLength = data.Length;
webRequest.Timeout = timeout;
requestStream = webRequest.GetRequestStream();
requestStream.Write(data, 0, data.Length);
webResponse = (HttpWebResponse)webRequest.GetResponse();
responseStream = webResponse.GetResponseStream();
if (responseStream == null) { return ""; }
streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encode));
return streamReader.ReadToEnd();
}
/// <summary>
/// Post文件流给指定Url
/// </summary>
/// <param name="url">url</param>
/// <param name="filePath">文件路径</param>
/// <returns>响应流字符串</returns>
public static string PostFile(string url, string filePath, string contentType = "application/octet-stream", string encode = "UTF-8")
{
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(filePath))
{
Stream requestStream = null;
Stream responseStream = null;
StreamReader streamReader = null;
FileStream fileStream = null;
try
{
// 设置参数
HttpWebRequest webRequest = WebRequest.Create(url) as HttpWebRequest;
SetAuth(webRequest);
webRequest.AllowAutoRedirect = true;
webRequest.Method = "POST";
string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
webRequest.ContentType = "multipart/form-data;charset=" + encode + ";boundary=" + boundary;
byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");//消息开始
byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");//消息结尾
var fileName = filePath.Substring(filePath.LastIndexOf("/") + 1);
//请求头部信息
string postHeader = string.Format("Content-Disposition:form-data;name=\"media\";filename=\"{0}\"\r\nContent-Type:{1}\r\n\r\n", fileName, contentType);
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);
fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
byte[] fileByteArr = new byte[fileStream.Length];
fileStream.Read(fileByteArr, 0, fileByteArr.Length);
fileStream.Close();
requestStream = webRequest.GetRequestStream();
requestStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
requestStream.Write(fileByteArr, 0, fileByteArr.Length);
requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
requestStream.Close();
responseStream = webRequest.GetResponse().GetResponseStream();//发送请求,得到响应流
if (responseStream == null) return string.Empty;
streamReader = new StreamReader(responseStream, Encoding.UTF8);
return streamReader.ReadToEnd();
}
catch (Exception ex)
{
}
finally
{
}
}
return null;
}
/// <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")
{
//HttpWebRequest对象
//HttpClient->dudu 调用预热处理
//Stream—>Model
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode))
{
Stream responseStream = null;
StreamReader streamReader = null;
WebResponse webResponse = null;
try
{
string respStr = GetRespStr(url, responseStream, streamReader, webResponse, timeout, encode);
return JsonHelper.JsonDeserialize<T>(respStr);
}
catch (Exception ex)
{
}
finally
{
if (responseStream != null) responseStream.Dispose();
if (streamReader != null) streamReader.Dispose();
if (webResponse != null) webResponse.Dispose();
}
}
return default(T);
}
/// <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))
{
Stream responseStream = null;
StreamReader streamReader = null;
WebResponse webResponse = null;
try
{
return GetRespStr(url, responseStream, streamReader, webResponse, timeout, encode);
}
catch (Exception ex)
{
}
finally
{
if (responseStream != null) responseStream.Dispose();
if (streamReader != null) streamReader.Dispose();
if (webResponse != null) webResponse.Dispose();
}
}
return null;
}
private static string GetRespStr(string url, Stream responseStream, StreamReader streamReader, WebResponse webResponse, int timeout, string encode)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "GET";
webRequest.Timeout = timeout;
webResponse = webRequest.GetResponse();
responseStream = webResponse.GetResponseStream();
if (responseStream == null) { return ""; }
streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encode));
return streamReader.ReadToEnd();
}