zoukankan      html  css  js  c++  java
  • IIS相关

    理解网站和虚拟目录

    IIS可以同时宿主多个不同的网站,我们对每一个网站指定一个根目录,这个目录可以是服务器的本机目录也可以在网络的其他地方,然后IIS就可以从它所管理的那些目录下寻找或获得相应静态或动态请求的内容给我们了。

    为了指导特定的HTTP请求到相应的相应网站,IIS允许我们配置“绑定”。所谓“绑定”就是将一个特定的IPTCP端口号、和HTTP主机名对应到特定的网站。如下图:


    说明:
    Windows7/IIS7.5

    作为一个额外的配置,你还可以在网站目录文件夹任意层级上添加虚拟目录,每一个虚拟目录表示IIS将从其他地方提取或获得内容返回给对该虚拟目录的请求,这取决于你建立的虚拟目录所指定的文件夹的位置(它同样可以在本机也可以在网络的其他地方)。虚拟目录的目的是让真实文件所在的位置与网站目录列表脱离关系,有点类似文件夹的“快捷方式”,虚拟目录的存在使得外界不知道我们的真实文件所在具体位置,个人感觉逻辑上的意义大于安全上的意义。


    说明:
    IIS7/IIS7.5中虚拟目录的显示

    对于每一个虚拟目录你还可以选择是否赋予它独立的应用程序地位。如果选择这样做,该虚拟目录对应的独立的应用程序就拥有自己独立的配置文件了,如果该独立的应用程序是个Asp.net应用程序的话,那么它的状态也是独立的啦,是与它的父级应用程序的状态无关的。显然,因为他们是相互独立的应用程序,所以被设置成独立的应用程序的这个虚拟目录中所运行的Asp.net完全可以是和父级不同的版本的Asp.net

    IIS6开始,IIS引入了应用程序池(application pools)。应用程序池用来隔离同一台服务器上的多个同时运行的应用程序,每一个应用程序池工作在一个独立的工作进程中,设定相应的最大内存和CPU使用量,进程回收时间表,等。每一个网站或设置为独立应用程序的虚拟目录应用程序都会被分配到建立起来的IIS的应用程序池的其中一个池中去。一般的话,每个应用程序应建立一个应用程序池而不是与其他应用程序共用。这样可以保证如果一个应用程序崩溃了不影响其他应用程序的正常运行。参考:应用程序池

    绑定网站到主机名、IP地址和端口

    因为同一个服务器可以宿主多个网站,所以就需要一个系统来分派请求到正确的Web应用程序。上文提到,我们可以绑定网站到一个或者多个:

    l 端口号

    l 主机名

    l IP地址(仅当服务器有多个IP地址时——比如有多个网络适配器)

    对于主机名和IP地址,你可以选择不做任何指定,不做任何指定等于是一个通配符,这样的话对于所有不匹配特定网站的请求就会匹配给它。如果多个网站具有相同的绑定设置的话,同一时间只可能有一个是可用的,其它的处于停掉的状态,否则就不唯一了,对吧。虚拟目录继承父级应用程序的绑定设置。

    IIS是如何处理进来的请求并调用ASP.NET

    IIS将接收到的一个请求分配给相应的网站的时候,它需要决定怎么来处理这个请求。它是要直接从磁盘返回一个静态内容呢,还是要调用网站应用程序执行它并动态地生成内容来返回呢?它是如何决定这些的?

    作为一个Asp.net MVC程序域,你需要理解IIS的这个机制,不仅是Asp.net MVC程序员,Asp.net程序员都需要理解这个机制(Asp.net程序员包含Asp.net MVC程序员)——至少应该有个基本了解;否则,你将会在理解进来的请求与你的路由配置映射时遇到困难。

    IIS6IIS7在传统模式下是如何处理请求的

    如果你没有使用IIS7的集成管线模式的话,你使用的将是回归到IIS5的传统管道模型。在这个模式下,IIS只能提供静态内容和具有特定扩展名的从而可以映射到相应的ISAPIURL返回的动态内容。

    IIS分析请求近来的URL,取得它的扩展名(比如:http://hostname/folder/file.aspx?foo=bar的扩展名是.aspx),将该扩展名发往相应的ISAPI扩展程序。对于IIS6IIS7来说,你都可以配置ISAPI扩展程序与扩展名的映射,对于IIS7来说,你还可以使用处理器映射配置工具(装的不是中文版IIS翻译不准,英文为Handler Mappings configuration tool),如下图所示。


    说明:
    Windows7/IIS7.5

    上图中*.aspx被配置给了aspnet_isapi.dllaspnent_isapi.dll这个非托管的dll在操作系统启动时就已经被IIS加载到了内存中,该dll与托管环境进行交互然后将控制权转交给该应用程序所在的隔离的应用程序域的.NET CLRCLR接到控制权后,接着实例化一个HttpRuntime类对象,然后调用该HttpRuntime实例对象的ProcessRequest方法从而驱动后续的处理,当ProcessRequest执行结束的时候封装请求上下文信息的HttpContext实例就被构建完成了,继续,进入Asp.net运行时管道(可能叫做管线会更好些,MSDN上翻译的是管线),这个管道就像是条工厂中车间的流水线,而这条流水线上加工的对象就是前面HttpRuntime实例化出来的那个封装请求上下文信息的HttpContext实例对象,每个HTTP模块和管道后端的HTTP处理程序都是一道加工工序,这些工序有的负责验证权限,有的负责Asp.net的状态管理等,我把这个过程不确定的归结为职责链模式(C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG路径下<httpModules>节点中注册了这些默认的HTTP模块),接下来就是在管道中按照HTTP模块注册的顺序挨个执行各个HTTP模块,最后到达管道尾端的HTTP处理程序,比如我们的Page类就是一个实现了IHttpHandler接口的处理程序。再往下就是控件以及页面生命周期等这些我们非常熟悉的东西了。值得说明的是,在我们的Global.asax中从System.Web.HttpApplication类继承而来的那个自定义类中按照约定的方式书写代码就是我们与所有这些Http模块们交互的方式了。其实对于System.Web.UI.Page的实例化实际上是通过工厂来返回的,上图注册*.aspx的时候就是注册到了默认的PageHandlerFactory工厂了,该工厂实例再根据前面所有那些步骤中一直存在的最后封装到了HttpContext中的请求的URL对应的文件名来查找相应文件名的的真实的.aspx文件,并读取该文件的第一行指令,指令指定了最终负责处理该请求的HTTP处理程序类,这个类就是我们编写的 System.Web.UI.Page类(一般是从Page继承过来的子类)。接下来服务器控件与组件以及页面的执行最终生成HTML页面内容,生成的HTML结果返回给开始的aspnet_isapi扩展最后被IIS输出。而控件以及页面生命周期等这些已经是我们非常熟悉的领域了。有兴趣的话你可以翻阅MSDN或者觉得有什么意义的话更进一步用Reflector沿着流程从System.Web.UI.PageHandlerFactory开始查看源代码。

    说明:Http模块就是实现了IHttpModule接口的类,Http处理程序就是实现了IHttpHandler接口的类。老赵说过:如果你不理解Http模块和Http处理程序的话就不能称为真正熟悉Asp.net,之所以要理解HttpModuleHttpHandler是因为理解了他们之后才能明明白白地基于HttpModuleHttpHandler进行编程,扩展我们的Asp.net应用程序管线中的内容(原话可能不是这样,意思应该是这样)。如果你想了解HttpModuleHttpHandler的话,有两本书非常值得推荐:微软出版社的《Asp.net 3.5技术内幕》和Wrox的《Asp.net 2.0服务器控件与组件高级编程》这两本书的相关章节都有对该主题较好的介绍。阅读小洋(燕洋天工作室)的浅谈ASP.NET内部机制系列或者张子阳的关于Asp.net的文章也是一个不错的选择。Asp.net MVCHttpModuleHttpHandler级别上与原来的Asp.net是完全一样的。

    Asp.net是如何被关联的

    在你安装.NET Framework的时候(或者执行aspnet_regiis.exe的时候),安装程序自动注册了*.aspx,*.axd,*.ashx,和其他一些扩展名到一个特殊的名字叫做aspnet_isapi.dllISAPI扩展程序。一个请求必须与一个注册过的扩展名相匹配,然后IIS将激活aspnet_isapi.dll,这个非托管的dll再把控制权转交给托管代码,接下来就是托管代码的时间了,.NET CLR在一个不同的进程中执行这些接下来的非托管代码。

    无后缀URL的问题

    传统上,该系统对Asp.net服务器页面来说一切正常,因为它们对应真实的以.aspx为后缀文件真实的存在与磁盘上。但是,对于新的路由系统来说就不是这样了,对于routing来说URL不需要与磁盘上的真实文件对应甚至不需要有扩展名。

    这个新的URL路由系统是作为一个.NET HTTP模块创建的。该HTTP模块是被假设为处理所有请求来创建的,该模块是判断和决定对一个请求的控制是否可以转入到你的Asp.net MVC项目的某个控制器并由该控制器来接待。但是这是.NET托管代码,所以只有在请求能够激活ASP.NET的条件下才能够往下进行(比如IIS将请求映射给了aspnet_isapi.dll)。所以除非该请求URL具有合适的扩展名,否则aspnet_isapi.dll根本不会被激活,这意味着IIS将会把该请求作为静态请求尝试返回相应于URL的静态文件的内容,因为磁盘上并没有这个静态文件存在,所以我们将得到一个404 Not Found错误。如何才能做到可以使用无扩展名的URL呢!我们大部分希望将Asp.net MVC项目部署到IIS6上的人开始都会遇到这个问题。接下来的文字中我们会给出四个解决方案以供选择。

    这部分内容太基础和透明,很难把握,对于存在的不正确的地方希望朋友们指出来,回头改正以免误导。下一篇真正进入Asp.net MVC的部署。
    ————————————————
    添加于2009.9.19

    ASP.NET执行循序

    首先第一次运行一个应用程序(WebSite或者WebApplication都是Web应用程序)
    第一次请求 ->

    1,IIS ->

    2,aspnet_isapi(非托管dll) ->

    3,HttpRuntime(到这里已经是托管的了)HttpRuntime中只有一个方法ProcessRequest 这个方法是整个应用程序的入口点 HttpContext就是在这个方法里面构建的 出了这个方法后HttpContext就构建完成了 ->

    4,执行HttpApplication类的Start方法(因为是第一次请求,HttpApplication还没有建立即应用程序池中还没有该站点的HttpApplication对象存在,再第二次请求的时候应用程序池中就已经有HttpApplicationd对象了就不会执行这个方法了 只有应用程序池里没有该站点的HttpApplication对象的时候才会执行这个方法) ->

    5,初始化各个HttpModule在HttpModule的Init方法中注册HttpApplication的事件方法 而Init中的HttpApplication就是那个新建立的或者从HttpApplication池中得到的那个->

    6,按照顺序执行HttpModule们注册给HttpApplication的事件方法 ->

    7,首先是Application的BeginRequest事件方法 这个事件的方法列表中的方法分散在任何地方 在HttpModule里有该事件的方法 所以后续的执行回反复进入HttpModule中去执行这些注册给HttpApplication事件的方法 其中HttpApplicaiton的事件方法在HttpApplication自己里面是按照约定的方法注册的 这里是约定的编程方式必须加上"HttpApplicaiton_"前缀 在HttpApplication_Start后的某个时候使用反射注册这些约定命名的方法到对应的HttpApplication的事件列表方法 ->

    8,接着按照HttpApplication中事件的顺序执行注册给HttpApplication余下事件的事件方法 在HttpApplication执行到中间的某个环节的时候开启执行HttpHandler HttpHandler执行完了 Application的最后的事件是EndRequest 执行HttpApplication的EndRequest事件方法列表中的方法 这些方法有的在HttpModule中所以最后又进入HttpModule HttpModule的Init方法是给HttpApplication注册事件方法的唯一地方 最后看注册给HttpApplication的事件方法列表总方法都是分别在哪里 由HttpApplication的事件执行顺序决定整个管道中的流程 HttpModule的Init方法是唯一一个可以访问HttpApplication对象的地方 HttpModule在Init里给这个HttpApplication对象注册事件把HttpModule的自己的方法作为HttpApplication的事件方法横插在HttpApplication的事件流程中

    HttpApplication的各个事件执行顺序就是所谓的管道 当一个请求进来的时候 IIS根据请求的Url把请求交给相应的站点 如果该站点是ASP.NET支持的话 HttpRuntime从HttpApplication应用程序池中取出一个HttpApplication对象 然后把这个取出来的HttpApplication对象交给HttpModule的Init(HttpApplication application)方法 HttpModule再给这个HttpApplication的“事件”插入“事件方法” 在HttpApplication中间会通过HttpHandlerFactory根据请求的Url的文件名以及扩展名决定经过哪一个HttpHandler 因为HttpHandler不是每一个都要经过的而是取决于Url的文件名和扩展名所以HttpHandler必不能保有对HttpApplication以及HttpModule这些对于每个请求都会经过的对象 否则的话HttpHandler就可以编程HttpApplication了 而这个HttpApplication会被放回HttpApplication应用程序池 就是网站应用程序池 也就是IIS上建立的那个池 那个池中存的就是该站点的HttpApplication对象
    注意:HttpApplication被放入IIS的ASP.NET Web应用程序对象池的事件是在所有的HttpModule的Init方法被执行之后 第二次请求的时候是不会再经过HttpModule了 但是因为有的HttpModule在Init中把自己的方法注册给了HttpApplication的事件 所以后面才会反复进入HttpModule去执行HttpApplication的事件方法 如果HttpModule的Init方法不是把自己的方法注册给HttpApplication而是这个方法在其他地方那就不会再进入HttpModule了 也就是HttpModule里只有一个方法Init这个方法跟HttpApplication的Start方法一样是只会被执行一次的

     

    IIS7的集成管线模式中请求是如何被处理的

    IIS7引入了一个激进的不同以前的管线模式,叫做集成管线模式,在这个模式中.NETWeb服务器本地支持的一部分。现在,IIS不再需要一个ISAPI扩展来激活.NET代码了——IIS7自己就可以搞定了,现在IIS7可以直接从.NET程序集中调用HTTP modulesHTTP handlers了。当然,如果你愿意的话,你仍然可以使用老的模式,依旧可以使用非托管的ISAPI扩展。

    IIS7中默认的模式是集成管线模式,但是如果你需要返回到传统的管线模式的话,是可以在应用程序池配置界面中对管线模式进行调整的。

    说明:图中显示默认添加了两个应用程序池,其中一个使用的传统管线模式,另一个是集成管线模式。

    说明:你可以在具体网站的高级设置中配置所使用的应用程序池。

    Asp.net是如何被关联的

    在集成管线模式中,IIS仍然根据URL文件扩展名来选择处理程序(ISAPI扩展或.NET IHttpHandler类或者HttpHandler工厂)。同样,你可以使用扩展名处理程序映射配置工具来配置扩展名和相应的处理程序。对ASP.NET请求来说不同的是,它不再需要通过aspnet_isapi.dll了——现在可以直接由IIS根据扩展名调用到相应的IHttpHandler处理程序了,比如默认的*.aspxSystem.Web.UI.PageHandlerFactory。当你在服务器上开启ASP.NET服务的时候,所有的这些映射都已经自动设置好了。以前则是IIS根据扩展名把请求交给aspnet_isapi.dllaspnet_isapi.dll再进一步根据扩展名甚至文件名把请求交给相应的IHttpHandler处理程序或者工厂的。

    说明:IIS7中默认使用的是集成管线模式,默认情况下传统模式也是开启了,所以就有两套扩展名与处理程序的映射配置,一套用于传统模式,一套用于集成模式。可以看到,上图显示的是集成模式的配置——具有*.aspx扩展名的URL配置为最终交给System.Web.UI.PageHandlerFactory进行处理。注意,别忘了在到达PageHandlerFactory之前是已经经过了各个注册的HttpModules的(在集成模式中,IIS不再需要一个非托管的ISAPI扩展程序来激活.NET代码了——IIS7自己就可以完成了,现在IIS7可以直接从.NET程序集中调用HTTP modulesHTTP handlers)。

    说明:该图显示的是传统模式下对应于*.aspx扩展名的配置,可以看出——传统模式下,具有*.aspx扩展名的URL是被IIS转交给aspnet_isapi.dll了的,aspnet_iaspi.dll后还有HttpRuntimeHttpModule,并最终到达System.Web.UI.PageHandlerFactory//可以参考上一篇

    集成管线模式是如何使得制造无后缀的URL变得如此Easy

    重述要点,一个IHttpHandler类负责终结处理一类请求,每一个请求只能被一个处理程序处理(根据请求URL的扩展名来决定被哪一个IHttpHandler类来处理)。相比之下,IHttpModule类是插入在处理请求的管线内的,并且你可以在单个请求的处理流程中插入任意多个此类的IHttpModule。在IIS7里,即使那些最终不是被ASP.NET处理的请求也是要经过这些注册了的IHttpModules的(不被ASP.NET处理的那些请求指的即是对非ASP.NET网站应用程序的请求,对静态文件的请求等此类请求)。//参考上一篇

    因为UrlRoutingModule是一个注册了的IHttpModule(不是IHttpHandler),所以所有的请求都要经过它,请求需要经过管线中的IHttpModules是与URL扩展名和处理程序映射无关的事情。在UrlRoutingModule被调用的时候,它根据你的路由配置使路由系统尝试匹配进来的URL请求信息,如果匹配到了第一个入口,接着就会把控制权转交给你的一个controller类(或者一个自定义的IRouteHandler)。

    UrlRoutingModule默认是被配置了的,因为当你创建一个新的空白的ASP.NET MVC网站应用程序的时候,你的web.config文件有一个<system.webServer>节点,如下:

    <system.webServer>

    <modules runAllManagedModulesForAllRequests="true">

    <remove name="ScriptModule"/>

    <remove name="UrlRoutingModule"/>

    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, ..."/>

    <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, ... "/>

    </modules>

    </system.webServer>

    <system.webServer>节点是IIS7存取你的应用程配置数据的地方。所以,当你部署到IIS7的时候,无后缀URL再不需要任何其他手动设置的情况下即可工作了(如果一个无后缀的URL匹配了你的MVC路由配置的话,根据URL和匹配规则,controlleraction即已经确定了。controller确定了,action确定了,再加上匹配的其他URL信息,包括QueryString,带着这些初始信息以及封装的请求上下文信息进入MVC框架,直到整个流程的完成都有源码供你阅读,因为ASP.NET MVC是开源的啊!赶快阅读它吧!另外微软开源的东西本来就少,并且从代码量上说ASP.NET MVC的规模刚好适合阅读,“它只有千余行核心代码//引用的老赵的话”相信你用几天的时间就可以搞通它了,并且相信你的收获会超出ASP.NET MVC本身之外。不阅读的人是傻瓜^_^)。嗯,现在我明白了为什么IIS7可以容易的制造出无后缀的URL了,你明白了吗?不失完整性,下面是关于Visual Studio 2008内置Web服务器的请求处理模式的。

    Visual Studio 2008的内置Web服务器中是如何处理请求的

    你可能已经注意到了,当你在Visual Studio 2008的内置Web服务器中运行你的应用程序的时候,路由系统工作正常(Yes!无后缀!)。这是因为webdev.webserver.exe总是交由ASP.NET处理所有的请求,所以UrlRoutingModule总是被调用了。

    但是,这可导致不愉快的事情发生,因为在我们随后将做好的Web应用程序部署到IIS6的时候事情变得复杂,发现事情并没有像在Visual Studio的集成Web服务器上那么简单。幸好,解决方案总是存在,下一遍一起学习。

    说实话,要是仅仅是部署ASP.NET MVC应用程序的话,并没有那么复杂,无需长篇累牍的扯蛋。如果通过这些文字能够对初学者的知识起到编织作用从而有助于形成知识体系的话,目的已经达到了。 

     转自xuefly的一篇文章http://www.cnblogs.com/xuefly/archive/2009/07/31/1535571.html

  • 相关阅读:
    4、Cocos2dx 3.0三,找一个小游戏开发Hello World 分析
    Android Bluetooth开发
    详细解析BluetoothAdapter的详细api
    Android 蓝牙( Bluetooth)耳机连接分析及实现
    [Andriod官方API指南]连接之蓝牙
    Android蓝牙A2dp profile的使用
    Android中文API(129) —— AudioManager
    Android中的Audio播放:控制Audio输出通道切换
    JAVA ANDROID SOCKET通信检测(SERVER)连接是否断开
    Android Xfermode 实战 实现圆形、圆角图片
  • 原文地址:https://www.cnblogs.com/EasyLive2006/p/2176715.html
Copyright © 2011-2022 走看看