• HttpWebRequest、HttpWebResponse、HttpClient、WebClient等http网络访问类的使用示例汇总


    工作中长期需要用到通过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 = 15000)
    {
        if (!IsConnectedInternet())
            return "网络连接错误,请稍后再试。";
    
        try
        {
            GC.Collect();
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Timeout = timeoutSeconds;
            request.Method = method.ToString();
            21         //如果是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, 0, 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("404"))
                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 = 300000;  //设置获得响应的超时时间(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 + "
    Content-Disposition: form-data; name="{0}";filename="{1}"
    Content-Type:application/octet-stream
    
    ";
        string header = string.Format(dataFormat, "file", Path.GetFileName(filePath));
        byte[] postHeaderBytes = Encoding.UTF8.GetBytes(header);
    
        //结束边界
        byte[] boundaryBytes = Encoding.ASCII.GetBytes("
    --" + timeStamp + "--
    ");
    
        long length = fileStream.Length + postHeaderBytes.Length + boundaryBytes.Length;
    
        httpReq.ContentLength = length;//请求内容长度
    
        try
        {
            //每次上传4k
            int bufferLength = 4096;
            byte[] buffer = new byte[bufferLength];
    
            //已上传的字节数
            long offset = 0;
            int size = binaryReader.Read(buffer, 0, bufferLength);
            Stream postStream = httpReq.GetRequestStream();
    
            //发送请求头部消息
            postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
    
            while (size > 0)
            {
                postStream.Write(buffer, 0, size);
                offset += size;
                size = binaryReader.Read(buffer, 0, bufferLength);
            }
    
            //添加尾部边界
            postStream.Write(boundaryBytes, 0, 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 = 3000;
    
            var stream = new MemoryStream();
    
            //头信息
            string dataFormat = "--" + boundary + "
    Content-Disposition: form-data; name="{0}"
    
    {1}
    ";
            foreach (string key in dic.Keys)
            {
                string s = string.Format(dataFormat, key, dic[key]);
                byte[] data = Encoding.UTF8.GetBytes(s);
                stream.Write(data, 0, data.Length);
            }
    
            //结束边界
            byte[] boundaryBytes = Encoding.ASCII.GetBytes("--" + boundary + "--");
            stream.Write(boundaryBytes, 0, 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 = 10)
    {
        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(0, 0, 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("404"))
                requestResult.Message = "连接服务器404,请重试";
            else
                requestResult.Message = e.Message;
            callback?.Invoke(requestResult);
        }
    }
    
    public static async void AsyncGet(string url, Action<RequestResult> callback, int timeoutSeconds = 10)
    {
        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(0, 0, 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("404"))
                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 = 10)
    {
        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(0, 0, 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("404"))
                requestResult.Message = "连接服务器404,请重试";
            else
                requestResult.Message = e.Message;
            callback?.Invoke(requestResult);
        }
    }
    
    public static async void AsyncDelete(string url, Action<RequestResult> callback, int timeoutSeconds = 10)
    {
        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(0, 0, 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("404"))
                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 = 0;
        return InternetGetConnectedState(ref description, 0);
    }
    
    #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[102400];
                        int realReadLen = netStream.Read(readbyte, 0, readbyte.Length);
                        while (realReadLen > 0)
                        {
                            fstr.Write(readbyte, 0, realReadLen);
                            realReadLen = netStream.Read(readbyte, 0, readbyte.Length);
                            Thread.Sleep(10);
                        }
                        netStream.Dispose();
                        fstr.Flush();
                        fstr.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("下载文件时出现异常。", ex);
            }
        });
    }

    以上,有需要的可以拿去使用,通用性还是能保证的,有特殊用途改改就可以了,比如微信公众平台上传文件时form-data内的name是media。

  • 相关阅读:
    Convolutional Neural Network-week1编程题(一步步搭建CNN模型)
    Coursera Deep Learning笔记 卷积神经网络基础
    爬取b站周杰伦新歌mv弹幕 绘制词云
    Coursera Deep Learning笔记 结构化机器学习项目 (下)
    Golang-执行go get私有库提示”410 Gone“ 解决办法
    golang常用的http请求操作
    关于asyncio知识(四)
    关于asyncio知识(二)
    Python Every Class Needs a __repr__
    关于asyncio知识(一)
  • 原文地址:https://www.cnblogs.com/lgx5/p/9446763.html
Copyright © 2020-2023  润新知