.Net HTTP请求的发送方式与分析

注:以下内容均来源于网络。

https://blog.csdn.net/chen213wb/article/details/81747573

https://blog.csdn.net/qq_23034515/article/details/89226635

https://www.cjavapy.com/article/50/

。。。

HTTP常用请求参数

Method

请求方式:Get、Post、Put、Delete

Timeout

获取或设置请求的超时值。(毫秒)

ReadWriteTimeout

获取或设置读取或写入流时的超时

KeepAlive

获取或设置一个值,该值指示是否与 Internet 资源建立持久性连接。

ClientCertificates

获取或设置与此请求关联的安全证书集合

Proxy

获取或设置请求的代理信息。

AllowAutoRedirect

获取或设置一个值,该值指示请求是否应跟随重定向响应。

CookieContainer

获取或设置与此请求关联的cookie。

Credentials

获取或设置请求的身份验证信息。

MaximumAutomaticRedirections

获取或设置请求将跟随的重定向的最大数目。

SendChunked

获取或设置一个值,该值指示是否将数据分段发送到 Internet 资源。

Header.ContentType

设置请求的数据类型:application/x-www-form-urlencoded、multipart/form-data、application/json、text/xml...

Header.ContentLength

设置请求的数据长度

Header.Accept

设置响应的数据类型:application/x-www-form-urlencoded、multipart/form-data、application/json、text/xml...

Header.UserAgent

客户端的访问类型,包括浏览器版本和操作系统信息

Header.Referer

请求的来源地址

 

请求方式:

1、GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的。

2、与GET不同的是,PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。

3、POST请求同PUT请求类似,都是向服务器端发送数据的,但是该请求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。几乎目前所有的提交操作都是用POST请求的。

4、DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。

就像前面所讲的一样,既然PUT和POST操作都是向服务器端发送数据的,那么两者有什么区别呢?POST主要作用在一个集合资源之上的(url),而PUT主要作用在一个具体资源之上的(url/xxx),通俗一下讲就是,如URL可以在客户端确定,那么可使用PUT,否则用POST。

综上所述,我们可理解为以下:

1、GET     /url/xxx  查看

2、PUT     /url/xxx  更新

3、POST    /url      创建  

4、DELETE  /url/xxx  删除  

 

数据类型:

1、application/x-www-form-urlencoded

浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。

2、multipart/form-data

我们使用表单上传文件时,必须让 form 的 enctyped 等于这个值。
种方式一般用来上传文件时必须使用该种方式,各大服务端语言对它也有着良好的支持。

3、application/json

这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。

4、text/xmlXML-RPC

协议简单、功能够用,各种语言的实现都有。它的使用也很广泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服务等等。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。 因XML 结构还是过于臃肿,一般场景用 JSON 会更灵活方便。

 

.NET发送HTTP请求的方式

1、HttpWebRequest

这是.NET创建者最初开发用于使用HTTP请求的标准类。使用HttpWebRequest可以让开发者控制请求/响应流程的各个方面,如 timeouts, cookies, headers, protocols。另一个好处是HttpWebRequest类不会阻塞UI线程。例如,当您从响应很慢的API服务器下载大文件时,您的应用程序的UI不会停止响应。HttpWebRequest通常和WebResponse一起使用,一个发送请求,一个获取数据。HttpWebRquest更为底层一些,能够对整个访问过程有个直观的认识,但同时也更加复杂一些。

这种方法是早期开发者使用的方法,在当前业务中已经很少使用,由于其更加底层,需要处理一些细节,最多用于框架内部操作。

    /// <summary>
    /// 1.通过WebRequest发送请求
    /// </summary>
    public class SendByWebRequest
    {
        public static string Post(string url,string content)
        {
            HttpWebRequest request = null;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                var data = Encoding.UTF8.GetBytes(content);
                request.Accept = "application/json"; // 设置响应数据的ContentType
                request.Method = "POST";
                request.ContentType = "application/json"; // 设置请求数据的ContentType
                request.ContentLength = data.Length;
                // 设置入参
                using (var stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
                // 发送请求
                var response = (HttpWebResponse)request.GetResponse();
                // 读取出参
                using (var resStream = response.GetResponseStream())
                {
                    using (var reader = new StreamReader(resStream, Encoding.UTF8))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                return null;
            }
            finally
            {
                // 释放连接
                if (request != null) request.Abort();
            }
        }

        public static string Get(string url, string content)
        {
            HttpWebRequest request = null;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url + content);
                request.Accept = "application/json"; // 设置响应数据的ContentType
                var response = (HttpWebResponse)request.GetResponse();
                // 读取出参
                using (var resStream = response.GetResponseStream())
                {
                    using (var reader = new StreamReader(resStream, Encoding.UTF8))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                return null;
            }
            finally
            {
                // 释放连接
                if (request != null) request.Abort();
            }
        }
    }

 

2、WebClient

WebClient是一种更高级别的抽象,是HttpWebRequest为了简化最常见任务而创建的,使用过程中你会发现他缺少基本的header,timeoust的设置,不过这些可以通过继承httpwebrequest来实现。相对来说,WebClient比WebRequest更加简单,它相当于封装了request和response方法,不过需要说明的是,Webclient和WebRequest继承的是不同类,两者在继承上没有任何关系。

使用WebClient可能比HttpWebRequest直接使用更慢(大约几毫秒),但却更为简单,减少了很多细节,代码量也比较少。

WebClient主要面向了WEB网页场景,在模拟Web操作时使用较为方便,但用在RestFul场景下却比较麻烦,这时候就需要HttpClient出马了。

    /// <summary>
    /// 2.通过WebClient发送请求
    /// </summary>
    public class SendByWebClient
    {
        public static string Post(string url, string content)
        {
            try
            {
                byte[] para = Encoding.UTF8.GetBytes(content);
                using (var client = new WebClient())
                {
                    client.Encoding = Encoding.UTF8;
                    client.Headers.Add("Accept", "application/json"); // 设置响应数据的ContentType
                    client.Headers.Add("Content-Type", "application/json"); // 设置请求数据的ContentType
                    client.Headers.Add("ContentLength", para.Length.ToString());
                    var response = client.UploadData(url, "POST", para);
                    return Encoding.UTF8.GetString(response);
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public static string Get(string url, string content)
        {
            try
            {
                using (var client = new WebClient())
                {
                    client.Encoding = Encoding.UTF8;
                    client.Headers.Add("Accept", "application/json"); // 设置响应数据的ContentType
                    return client.DownloadString(url + content);
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    }

 

 

3、HttpClient

目前业务上使用的比较多的是HttpClient,它适合用于多次请求操作,一般设置好默认头部后,可以进行重复多次的请求,基本上用一个实例可以提交任何的HTTP请求。此外,HttpClient提供了异步支持,可以轻松配合async await 实现异步请求。

HttpClient推荐使用单一实例共享使用,发关请求的方法推荐使用异步的方式。

    /// <summary>
    /// 3.通过HttpClient发送请求
    /// </summary>
    public class SendByHttpClient
    {
        public static string Post(string url, string content)
        {
            try
            {
                using (HttpClient client = new HttpClient())
                {
                    client.DefaultRequestHeaders.ExpectContinue = false; // httpclient默认开启expect,而有些服务器不会正确应答,容易导致请求无法提交
                    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); // 设置响应数据的ContentType
                    var para = new StringContent(content);
                    para.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); // 设置请求数据的ContentType
                    return client.PostAsync(url, para).Result.Content.ReadAsStringAsync().Result;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public static string Get(string url, string content)
        {
            try
            {
                using (HttpClient client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); // 设置响应数据的ContentType
                    return client.GetStringAsync(url + content).Result;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }


    }

 

4、第三方类库

Flurl.Http,RestSharp等。

    /// <summary>
    /// 4.通过第三方类库发送请求
    /// </summary>
    public class SendByFlurl
    {
        public static string Post(string url, string content)
        {
            try
            {
                //string abc = $"{url}".PostJsonAsync(content).ReceiveString().Result;
                return $"{url}".PostAsync(new StringContent(content, Encoding.UTF8, "application/json")).ReceiveString().Result;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public static string Get(string url, string content)
        {
            try
            {
                return $"{url}{content}".GetStringAsync().Result;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    }

 

 

 

HttpWebRequset

WebClient

HttpClient

命名空间

System.Net

System.Net

System.Net.Http

继承类

WebRequest

Component

HttpMessageInvoker

支持url转向

支持cookie和session

支持用户代理服务器

使用复杂度

 

 

扩展

REST & RPC

  微服务之间的接口调用通常包含两个部分,序列化和通信协议。常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等;通信比较流行的是http、soap、websockect,RPC通常基于TCP实现,常用框架例如dubbo,netty、mina、thrift。

  REST:严格意义上说接口很规范,操作对象即为资源,对资源的四种操作(post、get、put、delete),并且参数都放在URL上,但是不严格的说Http+json、Http+xml,常见的http api都可以称为Rest接口。

  RPC:即我们常说的远程过程调用,就是像调用本地方法一样调用远程方法,通信协议大多采用二进制方式。

HTTP vs 高性能二进制协议

  HTTP相对更规范,更标准,更通用,无论哪种语言都支持HTTP协议。如果你是对外开放API,例如开放平台,外部的编程语言多种多样,你无法拒绝对每种语言的支持,相应的,如果采用HTTP,无疑在你实现SDK之前,支持了所有语言,所以,现在开源中间件,基本最先支持的几个协议都包含RESTful。

  RPC协议性能要高的多,例如Protobuf、Thrift、Kyro等,(如果算上序列化)吞吐量大概能达到http的二倍。响应时间也更为出色。千万不要小看这点性能损耗,公认的,微服务做的比较好的,例如,netflix、阿里,曾经都传出过为了提升性能而合并服务。如果是交付型的项目,性能更为重要,因为你卖给客户往往靠的就是性能上微弱的优势。

  所以,最佳实践一般是对外REST,对内RPC,但是追求极致的性能会消耗很多额外的成本,所以一般情况下对内一般也REST,但对于个别性能要求较高的接口使用RPC。

 

常见问题:

1.最近项目使用HttpClient发送post请求时,发现请求一直卡住发不到服务端,而使用postman调用则正常。使用fiddler对比两者差异发现,HttpClient请求头有一个【Expect: 100-continue】。

  在网上查知,HttpClient是默认开启Expect协议头的,但是不是所有服务器都能正常响应100-continue。所以需要关闭该配置:client.DefaultRequestHeaders.ExpectContinue = false;

 

posted @ 2019-11-12 10:35  Ariter  阅读(2270)  评论(0编辑  收藏  举报