HTTP在.NET中的一些应用和解析

     谈到HTTP协议(超文本传输协议),HTTP协议是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。

    HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。HTTP协议的主要特点可概括为:1.支持客户/服务器模式。2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。3.灵活:HTTP允许传输任意类型的数据对象。4.无连接:无连接的含义是限制每次连接只处理一个请求。5.无状态:HTTP协议是无状态协议。

    在.NET框架里面对HTTP协议的处理主要采用WebRequest对象,在我们的.NET项目中如果需要生成HTTP请求或者处理HTTP请求,会运用HttpWebRequest和HttpWebResponse对象。在实际项目的开发中,有一些需求需要同地方平台进行数据交互,例如我们经常使用的微信,支付宝,QQ等等平台,这就需要我们在自己的项目中生成对应的HTTP请求和处理相关HTTP请求信息。

    如何在我们的系统中后台生成对应的HTTP请求,这个事情就需要对HTTP协议做一个简单的了解:

    HTTP请求由三部分组成,分别是:请求行、消息报头、请求正文。HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文。HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始行(对于请求消息,开始行就是请求行,对于响应消息,开始行就是状态行),消息报头(可选),空行(只有CRLF的行),消息正文(可选)组成。

    现在提供一个较为通用的处理HTTP请求的代码,此部分主要是生成同步HTTP请求。

    在谈到.NET的同步中,需要介绍一下同步和异步的相关内容:

   同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是出于阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。  

    异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。 

     (以上的图都是从别处截的,感谢提供资料的博主们。)

    现在直接给出相关代码:

         /// <summary>
         /// 访问次数字典
        /// </summary>
        private readonly ConcurrentDictionary<string, int> _urlTryList = new ConcurrentDictionary<string, int>();
       /// <summary>
        /// Post数据
        /// </summary>
        public String PostData { set; private get; }
        /// <summary>
        /// 同步请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="tryTimes">错误重试次数</param>
        public string SyncRequest(string url, int tryTimes = 3)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException(url);
            }
            Trace.TraceInformation(string.Concat("开始同步请求:", url));
            _urlTryList.TryAdd(url, tryTimes);
            //创建并定义HTTP请求相关信息
            var request = WebRequest.Create(url) as HttpWebRequest;
            if (request == null) return string.Empty;
            request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            request.Headers.Add("Accept-Language", "zh-CN,zh;q=0.8");
            request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.None;
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            request.UseDefaultCredentials = false;
            request.KeepAlive = false;
            request.PreAuthenticate = false;
            request.ProtocolVersion = HttpVersion.Version10;
            request.UserAgent =
                "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36";
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
            request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
            request.Timeout = 1000 * 60 * 3;
            request.CookieContainer = CookieContainer;
            request.AllowAutoRedirect = true;
            //判断POST请求是否为空
            if (!string.IsNullOrEmpty(PostData))
            {
                request.ContentType = "application/x-www-form-urlencoded";
                request.Method = "POST";
                using (var postStream = request.GetRequestStream())
                {
                    var byteArray = Encoding.GetBytes(PostData);
                    postStream.Write(byteArray, 0, PostData.Length);
                    postStream.Close();
                }
            }
            else
            {
                request.AllowWriteStreamBuffering = false;
            }
            try
            {
                using (var response = request.GetResponse() as HttpWebResponse)
                {
                    if (response != null)
                    {
                        if (response.StatusCode != HttpStatusCode.OK)
                        {
                            Trace.TraceError(string.Concat("请求地址:", request.RequestUri, " 失败,HttpStatusCode",
                                response.StatusCode));
                            return string.Empty;
                        }
                        using (var streamResponse = response.GetResponseStream())
                        {
                            if (streamResponse != null)
                            {
                                if (!IsText(response.ContentType))
                                {
                                    var contentEncodingStr = response.ContentEncoding;
                                    var contentEncoding = Encoding;
                                    if (!string.IsNullOrEmpty(contentEncodingStr))
                                        contentEncoding = Encoding.GetEncoding(contentEncodingStr);
                                    var streamRead = new StreamReader(streamResponse, contentEncoding);
                                    var str = streamRead.ReadToEnd();
                                    if (CallBackAction != null && !String.IsNullOrEmpty(str))
                                        CallBackAction.BeginInvoke(str, request.RequestUri.ToString(), (s) => { }, null);
                                    return str;
                                }
                                //创建并指定文件夹
                                var fileName = string.Concat(DateTime.Now.ToString("yyyyMMdd"), "/", DateTime.Now.ToString("yyyyMMddHHmmssffff"),
                                    Path.GetExtension(request.RequestUri.AbsoluteUri));
                                var fileDirectory = Path.Combine(FileSavePath, DateTime.Now.ToString("yyyyMMdd"));
                                if (!Directory.Exists(fileDirectory))
                                    Directory.CreateDirectory(fileDirectory);
                                try
                                {
                                    //下载文件
                                    using (var fileStream = new FileStream(Path.Combine(FileSavePath, fileName), FileMode.Create))
                                    {
                                        var buffer = new byte[2048];
                                        int readLength;
                                        do
                                        {
                                            readLength = streamResponse.Read(buffer, 0, buffer.Length);
                                            fileStream.Write(buffer, 0, readLength);
                                        } while (readLength != 0);
                                    }
                                    if (CallBackAction != null && !String.IsNullOrEmpty(fileName))
                                        CallBackAction.BeginInvoke(fileName, request.RequestUri.ToString(), (s) => { }, null);
                                    return fileName;
                                }
                                catch (IOException ex)
                                {
                                    throw new IOException(ex.Message, ex);
                                }
                            }
                        }
                        response.Close();
                    }
                }
            }
            catch (WebException ex)
            {
                Trace.TraceError(string.Concat("请求地址:", request.RequestUri, " 失败信息:", ex.Message));
                var toUrl = request.RequestUri.ToString();
                if (_urlTryList.TryGetValue(toUrl, out tryTimes))
                {
                    _urlTryList.TryUpdate(toUrl, tryTimes, tryTimes - 1);
                    if (tryTimes - 1 <= 0)
                    {
                        _urlTryList.TryRemove(toUrl, out tryTimes);
                        Trace.TraceError(string.Concat("请求地址重试失败:", request.RequestUri));
                        return string.Empty;
                    }
                    SyncRequest(toUrl);
                }
            }
            finally
            {
                request.Abort();
            }
            return string.Empty;
        }

    以上就是对相关概念和代码的解析。有写的不到位的地方,敬请谅解。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏林德熙的博客

如何使用 C# 爬虫获得专栏博客更新排行

昨天,梦姐问我们,她存在一个任务,找到 关注数排行100 和 浏览量排行100 的专栏博客,在2017年还有更新的专栏。 梦姐说他要出去一趟,M大神在吃饭,于是...

431
来自专栏小曾

web安全:QQ号快速登录漏洞及被盗原理 web安全:通俗易懂,以实例讲述破解网站的原理及如何进行防护!如何让网站变得更安全。

为什么你什么都没干,但QQ空间中却发了很多小广告?也许你的QQ账号已经被盗。本文将讲解一个QQ的快速登录的原理。

972
来自专栏顶级程序员

11个让你吃惊的Linux终端命令

我已经用了十年的Linux了,通过今天这篇文章我将向大家展示一系列的命令、工具和技巧,我希望一开始就有人告诉我这些,而不是曾在我成长道路上绊住我。 ? 1.命...

4647
来自专栏Android群英传

Google I/O 之 Android App Bundles 是个啥

1032
来自专栏FreeBuf

手把手教你构建8个GPU的破密码机

长话短说 这台密码破解机既不需要任何的“黑魔法”,也不需要你花大量时间和精力去组装各种乱七八糟的零配件。如果你按照这篇文章给出的方法来进行设备组装的话,你应该可...

2746
来自专栏小灰灰

Chrome扩展程序之编码&时间戳小工具

Chrome扩展程序之编码&时间戳小工具 作为一个前端小白,对于chrome扩展程序久闻大名,实际动手头一次;前天晚上到前端哪里串门看到小伙伴在搞这个,要了份...

1958
来自专栏何俊林

Android支付实践(三)之银联支付功能(客户端+服务端)

前言:由于支付宝和微信支付都须要提供这个那个的认证材料,对于个人开发者想尝试,确实有不少麻烦,今天介绍的银联支付,对于个人开发者,可以说是福音了。来自chent...

3368
来自专栏向治洪

Mac 高效工作指南

序 很多做开发的程序员,都喜欢用mac,其绚丽的外观,加上手感体验,很适合开发和装逼用。其实除了这些为什么那么多程序员喜欢用mac呢,分析了一下使用mac的好处...

33410
来自专栏企鹅号快讯

11个让你吃惊的Linux终端命令

我已经用了十年的linux了,通过今天这篇文章我将向大家展示一系列的命令、工具和技巧,我希望一开始就有人告诉我这些,而不是曾在我成长道路上绊住我。 ? 1. 命...

1769
来自专栏阮一峰的网络日志

版本控制入门插图教程

但是,我平时只是业余写一些小程序,感觉特地装一个VCS太麻烦,所以一直没有用。最近,因为想认真做一个中等规模的项目,所以决心好好学一下怎么用。

592

扫码关注云+社区