美文网首页
HTTP与IIS服务浅入

HTTP与IIS服务浅入

作者: Memoyu | 来源:发表于2019-04-29 15:26 被阅读0次

      认知尚浅,如有错误,愿闻其详!

      最近刚接触ASP.NET,在此之前对于Web开发方面没有过多的了解,更不懂得浏览器访问网页的整个大概的过程经历了什么,整个思维模式仍停留在客户端开发C/S模式下,所以,有个比较浅显的制作简单IIS服务器例子来搞懂ASP.NET的大概处理过程来过渡,尤为重要。那我们就来学习这个例子。

      首先,我们了解一下HTTP是啥?

      HTTP是一种传输协议,全称(HyperText Transfer Protocol)超文本传输协,目的是为了规范请求与接收HTML页面的方法。只有根据协议包装报文数据(请求报文,响应报文),才能够正常的解析与处理响应。报文具体结构如下:
    HTTP请求报文:

    请求报文.png

    其结构分为请求头、状态行、空行和请求体(GET则为空)四个部分组成,上图给为请求报文>的一般格式。

    HTTP响应报文:

    响应报文.png

    响应报文与请求报文结构类似,如上图。

    详情可转至该文:https://blog.csdn.net/lhx_ldm/article/details/80338211

    IIS服务

    IIS全称Internet Information Service,中文名:Internet信息服务,专用于微软操作系统平台,兼容微软的各项Web技术,尤其是ASP.NET。用于Web网页的浏览的信息处理,也就是网站服务器。其处理ASP.NET的大概过程如下图。


    ASP请求编译流程图.png

    详情可转至该文:https://blog.csdn.net/qq_35393869/article/details/81182237

    SimpleIIS例子

    这是我在学习的过程中做的思维导图,如下图,然后根据思维导图再做出项目。IIS其内部处理简单的分为三大块:请求报文解析(HttpRequest)、报文处理(HttpApplication)、响应报文回传(HttpResponse),其基本的通信是通过Socket通信来实现,

    SimpleIIS.png

    代码

    由于项目文件挺多的,代码量也挺多,篇幅过大,就不一一展示
    服务器端
    服务器不断地侦听接收客户端发来的请求,然后进行处理
    服务端参考Socket实现:https://www.cnblogs.com/memoyu/p/10764884.html

     //1、初始化解析 请求报文 。
    HttpContext context = new HttpContext(msgStr);
    
    //2、处理请求报文,处理响应报文。
    HttpApplicaton applicaton = new HttpApplicaton();
    applicaton.ProcessRequest(context);
    //3、返回响应内容
    proxSocket.Send(context.httpResponse.GetHttpResponseHeader());//返回响应头
    proxSocket.Send(context.httpResponse.body);
    //4、关闭连接
    proxSocket.Shutdown(SocketShutdown.Both);
    proxSocket.Close();
    

    处理请求信息(HttpApplication)
    获取HttpRequest解析的请求头信息,然后对请求信息进行处理,本质是对HTML的解析,与动态页面的数据填充和整合,然后响应给客户端。请求可是请求静态页面和动态页面,静态页面直接将数据组合入响应体返回,动态页面则需要执行C#代码(执行的方式是通过反射,然后创建IHttpHandler对象,执行接口方法ProcessRequest方法),然后将动态数据组合入响应体返回。

     /// <summary>
            /// 实现接口,处理报文
            /// </summary>
            /// <param name="context"></param>
            public void ProcessRequest(HttpContext context)
            {
                #region 处理动态文件请求
                string ext = Path.GetExtension(context.httpRequest.url);//通过请求的地址获得请求文件拓展名
                if (ext == ".aspx")//如果是.aspx文件
                {
                    //通过反射的方式去实例化对应类,执行其内部方法,实现处理动态页面
                    var className = Path.GetFileNameWithoutExtension(context.httpRequest.url);//获得不具有拓展名的路径
                    IHttpHandler obj = Assembly.Load("SimpleIIS").CreateInstance("SimpleIIS." + className) as IHttpHandler;//通过反射创建对象
                    obj.ProcessRequest(context);//执行动态页面处理
                    return;
                }
                #endregion
                #region 静态页面处理
                //获得请求路径
                // context.httpRequest.url  例如:/web/sujin.html  相对路径
                string basePath = AppDomain.CurrentDomain.BaseDirectory;//获取程序的bin/Debug目录,相当于网站的根目录,
                string fileName = Path.Combine(basePath, context.httpRequest.url.TrimStart('/'));//拼接url 获得请求页面的绝对路径  ,源于url地址开头带有/,所以需要先去除在拼接
                if (!File.Exists(fileName))//判断请求文件是否存在
                {
                    context.httpResponse.stateCode = "404";//设置响应报文参数
                    context.httpResponse.stateDescribe = "Not Found";
                    context.httpResponse.contentType = "text/html";
                    string noExistHtml = Path.Combine(basePath , @"web\404.html");//拼接404页面地址
                    context.httpResponse.body = File.ReadAllBytes(noExistHtml);//将404.html页面加入响应体
                }
                else
                {
                    context.httpResponse.stateCode = "200";//设置响应报文参数
                    context.httpResponse.stateDescribe = "Ok";
                    context.httpResponse.contentType = GetContentType(Path.GetExtension(context.httpRequest.url));//获得请求文件类型
                    context.httpResponse.body = File.ReadAllBytes(fileName);//将请求文件写加入响应体
                }
    
                #endregion
    
            }
            /// <summary>
            /// 根扩展名获得请求的文件类型
            /// </summary>
            /// <param name="ext">扩展名</param>
            /// <returns>响应文件类型</returns>
            public string GetContentType(string ext)
            {
                string type = "text/html; charset=UTF-8";
                switch (ext)
                {
                    case ".aspx":
                    case ".html":
                    case ".htm":
                        type = "text/html; charset=UTF-8";
                        break;
    
                    case ".png":
                        type = "image/png";
                        break;
                    case ".gif":
                        type = "image/gif";
                        break;
                    case ".jpg":
                        type = "image/jpg";
                        break;
                    case ".jpeg":
                        type = "image/jpeg";
                        break;
                    case ".css":
                        type = "text/css";
                        break;
                    case ".js":
                        type = "application/x-javascript";
                        break;
                    default:
                        type = "text/plain; charset=gbk";
                        break;
                }
                return type;
            }
    

    请求头的处理(HttpRequest)

      /// <summary>
            /// 请求解析构造函数,解析请求,对应赋值属性
            /// </summary>
            /// <param name="requestStr"></param>
            /* 
             * 请求体:
             GET / HTTP/1.1
             Host: 192.168.0.4:45000
             Connection: keep-alive
             Upgrade-Insecure-Requests: 1
             User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36
             Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3
             Accept-Encoding: gzip, deflate
             Accept-Language: zh-CN,zh;q=0.9
             */
            public HttpRequest(string requestStr)
            {
                string[] lines = requestStr.Replace("\r\n" , "\r").Split('\r'); //源于splite只能处理单个字符,所以的将\r\n替换成\r
                httpMethod = lines[0].Split(' ')[0];//赋值请求的方法
                url = lines[0].Split(' ')[1];//赋值请求连接
                httpVersion = lines[0].Split(' ')[2];//赋值http版本号
            }
    

    响应报文处理(HttpResponse)

     /// <summary>
            /// 拼接响应头数据
            /// </summary>
            /// <returns></returns>
            public byte[] GetHttpResponseHeader()
            {
                string strResponseHeader = string.Format(@"HTTP/1.1 {0} {1}
    Content-Type: {2}
    Accept-Ranges: bytes
    server: Microsoft-IIS/8.5
    X-Powered-By: ASP.NET
    Date: Sat, 23 Nov 2019 08:43:15
    Content-Length: {3}
    
    ",stateCode , stateDescribe , contentType , body.Length);
    
                return Encoding.Default.GetBytes(strResponseHeader);
            }
    

    模拟动态页面
    一般状况下,我们访问的网页都是动态的,所以,实现动态网页功能是必要的,我们不仅可以请求静态页面,动态的也需要处理,ASP.NET中动态页面为.aspx 和 .ashx,类似如下结构。

     public class DynamicPage_1 : IHttpHandler
        {
            /// <summary>
            /// 实现接口方法
            /// </summary>
            /// <param name="context"></param>
            public void ProcessRequest(HttpContext context)
            {
                string str = string.Format("<html><head></head><body><h3>{0}<h3></body></html>", DateTime.Now.ToString());//动态生成html内容,时间
    
                context.httpResponse.stateCode = "200";//赋值响应头
                context.httpResponse.stateDescribe = "Ok";
                context.httpResponse.contentType = "text/html";
                context.httpResponse.body = Encoding.Default.GetBytes(str);//赋值响应体
            }
        }
    

    效果展示

    我在bin/Debug/web目录下放了保存的两个静态页面.


    静态页面.png SimpleIIS.gif

    相关文章

      网友评论

          本文标题:HTTP与IIS服务浅入

          本文链接:https://www.haomeiwen.com/subject/kbbagqtx.html