WPF开发-网络请求

2022-09-02 16:50:53 浏览数 (1)

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方法

代码语言:javascript复制
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

支持用户代理服务器

使用复杂度

0 人点赞