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 + "\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 = 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 + "\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, 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。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值