IHttpModule与IHttpHandler的区别整理
1.先后次序.先IHttpModule,后IHttpHandler. 注:Module要看你响应了哪个事件,一些事件是在Handler之前运行的,一些是在Handler之后运行的
2.对请求的处理上:
IHttpModule是属于大小通吃类型,无论客户端请求的是什么文件,都会调用到它;例如aspx,rar,html的请求.
IHttpHandler则属于挑食类型,只有ASP.net注册过的文件类型(例如aspx,asmx等等)才会轮到调用它.
3.IHttpHandler按照你的请求生成响应的内容,IHttpModule对请求进行预处理,如验证、修改、过滤等等,同时也可以对响应进行处理    HttpHandler是HTTP请求的处理中心,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。
    HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。

IHttpModule接口的声明:
        public interface IHttpModule
        {
            void Init (HttpApplication context);
            void Dispose ();
        }
        Init 方法:系统初始化的时候自动调用,这个方法允许HTTP模块向HttpApplication 对象中的事件注册自己的事件处理程序。
        Dispose方法: 这个方法给予HTTP模块在对象被垃圾收集之前执行清理的机会。此方法一般无需编写代码。

示例:把硬盘上的图片以流的方式写在页面上
        class TestHandler : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                byte[] b = new byte[fs.Length];
                fs.Read(b, 0, (int)fs.Length);
                fs.Close();
                context.Response.OutputStream.Write(b, 0, b.Length);
            }
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
        }
        Web.Config配置文件
      <httpHandlers>
       <add verb="*" path="*" type="ClassLibrary831.TestHandler,ClassLibrary831"></add>
      </httpHandlers> 
           Verb属性:指定了处理程序支持的HTTP动作。*-支持所有的HTTP动作;“GET”-支持Get操作;“POST”-支持Post操作;“GET, POST”-支持两种操作。 
Path属性:指定了需要调用处理程序的路径和文件名(可以包含通配符)。“*”、“*.aspx”、“showImage.aspx”、“test1.aspx,test2.aspx”
Type属性:用名字空间、类名称和程序集名称的组合形式指定处理程序或处理程序工厂的实际类型。ASP.NET运行时首先搜索bin目录中的DLL,接着在GAC中搜索。 
        这样程序运行的效果是该网站的任何一个页面都会显示worm.jpg图片。

首先,来了解一下IIS系统。它是一个程序,负责对网站的内容进行管理,以及对客户的请求(就是Http请求)做出反应。当用户对一个页面提出请求时,IIS做如下反应(忽略权限):
1.把对方请求的虚拟路径转换成物理路径
2.根据物理路径搜索请求的文件
3.找到文件后,获取文件的内容
4.生成Http头信息。
PS:关于IIS和IE生成的Http头信息(元数据),它是IE的一个插件,专门查看头信息的。
5.向客户端发送所有的文件内容:首先是头信息,然后是Html内容,最后是其它文件的内容。
6.客户端IE浏览器获得信息后,解析文件内容,找出其中的引用文件,如.js .css .gif等,向IIS请求这些文件。
7.IIS获取请求后,发送文件内容。
8.当浏览器获取所有内容后,生成内容界面

但是IIS有个缺点,即它仅仅支持静态html页面的内容,就是说,他只能分析如.htm,.html这样的文件内容。像一些动态内容的页面,含有服务器端操作代码的页面类型,如.asp,.aspx,.cgi,.php等,IIS不认识这些专用的标记,它就会把它当作文本,丝毫不做处理发送到客户端。

为了解决这个问题。IIS推出了一种机制,叫做ISAPI扩展(标准组件(COM组件)、过滤器+跳转程序),如果安装了专门的扩展,那么在访问IIS所不能处理的文件时,如.asp和.aspx文件,IIS就会在自己的进程里面启动这个扩展。刚才说了,ISAPI首先是个过滤器,他在注册到IIS的时候,会把每个扩展可以处理的文件扩展名注册到IIS里面。扩展启动后,就根据定义好的方式来处理IIS所不能处理的文件,然后把控制权跳转到专门处理代码的进程中。让这个进程开始处理代码,生成标准的HTML代码,生成后把这些代码加入到原有的Html中,最后把完整的Html返回给IIS,IIS再把内容发送到客户端。

客户端向web服务器*.aspx页面,http请求被inetinfo.exe进程截获(www服务),判断文件后缀之后,把这个请求转交给ASPNET_ISAPI.DLL而ASPNET_ISAPI.DLL则会通过一个Http PipeLine的管道,将这个http请求发送给ASPNET_WP.EXE进程,之后.net framework通过HttpRuntime处理这个Http请求,处理完毕后将结果返回给客户端。
当http请求被送入到HttpRuntime后,请求继续被送入到HttpApplication Factory容器当中,而这个容器给出一个HttpApplication实例来处理传递进来的http请求,而后依次进入到如下几个容器中:
HttpModule --> HttpHandler Factory --> HttpHandler
当系统内部的HttpHandler的ProcessRequest方法处理完毕之后,整个Http Request就被处理完成了,客户端也就得到相应的东东了。
完整的http请求在asp.net framework中的处理流程

HttpModule生命周期示意图

HttpRequest-->inetinfo.exe->ASPNET_ISAPI.DLL-->Http Pipeline-->ASPNET_WP.EXE-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
如果想在中途截获httpRequest并做些自己的处理,就应该在HttpRuntime运行时内部来做到这一点,确切的说是在HttpModule这个容器中做到这个的。
系统本身的HttpModule实现一个IHttpModule的接口,当然我们自己的类也能够实现IHttpModule接口,这就可以替代系统的HttpModule对象了。
一个Http请求在被ASP.NET Framework捕获之后会依次交给HttpModule以及HttpHandler来处理。hm与hh之间不是完全独立的,实际上,http请求在hm传递的过程中会在某个事件内将控制权转交给hh的,而真正的处理在HttpHandler中执行完成后,HttpHandler会再次将控制权交还给HttpModule

IHttpHandler接口中最重要的方法ProcessRequest(HttpHandler用来处理Http请求),当一个Http请求经过由HttpModule容器传递到HttpHandler容器中的时候,framework会调用HttpHandler的ProcessRequest方法来做对这个Http请求做真正的处理。
framework实际上并不是直接把相关页面的HTTP请求定位到一个内部默认的IHttpHandler容器之上的,而是定位到了其内部默认的IHttpHandler Factory上了。IHttpHandler Factory的作用就是对很多系统已经实现了的IHttpHandler容器进行调度和管理的,这样做的优点是大大增强了系统的负荷性,提升了效率。

IIS如何确定请求的处理程序

1. 给定一个url请求,IIS需要确定它的文件名,扩展名,以及最相似的与本请求资源合适的"ScriptMaps"metadata (缓存的ISAPI扩展 - 应用程序扩展名映射列表);

2. IIS检查是否有设定了的应用程序通配符,若有则匹配第一条应用程序扩展名映射

如果这个扩展映射返回“我不处理这类请求”,IIS将继续查找下一个,直到找到匹配的;

3. 如果没有通配符处理这个请求,然后IIS开始根据请求的扩展名,来依次匹配每个ScriptMaps,来确定合适的应用程序来处理。如果找到合适的应用程序扩展,IIS就会调用相应的程序来处理这个请求;

4. 如果没有应用程序扩展处理此请求,并且扩展名是危险的包含exe/dll类型,IIS会调用CGI/ISAPI 来处理请求;

5. 如果任然没有程序可以处理这个请求,IIS内嵌的静态文件处理器将接管,并做如下处理:

a、确定文件有效性:是否需要转向302请求,如果转向成功则ok;

b、如果请求是一个文件形式,则发送该文件给客户端;

c、如果设定了默认页面,然后就会查看默认页面列表,找到一个实际存在的可用的默认页面。如果定为到某个页面,然后就会做一个内部的url请求,来请求这个页面。

d、如果目录浏览权限是允许的,就会列出目录列表;

e、如果请求依然未被处理,就会产生 403.14 (拒绝访问)错误;

如何使用HttpModule来实现我们日常的应用:
        HttpModule通过在某些事件中注册,把自己插入ASP.NET请求处理管道。当这些事件发生的时候,ASP.NET调用对相应的HTTP模块,这样该模块就能处理请求了。
       1、向每个页面动态添加一些备注或说明性的文字:
            有了HttpModule我们就可以很简单地解决这个问题了。HttpModule是客户端发出请求到客户端接收到服务器响应之间的一段必经之路。我们完 全可以在服务器处理完请求之后,并在向客户端发送响应文本之前这段时机,把这段注释文字添加到页面文本之后。这样,每一个页面请求都会被附加上这段注释文 字。
            这段代码究竟该在哪个事件里实现呢? PostRequestHandlerExecute和PreSendRequestContent之间的任何一个事件都可以,但我比较喜欢在EndRequest事件里编写代码。
            第一步:创建一个类库ClassLibrary831。
            第二步:编写一个类实现IHttpModule接口
                class TestModule:IHttpModule
                {
                    public void Dispose()
                    {
                    }
                    public void Init(HttpApplication context)
                    {
                    }
                } 
            第三步:在Init事件中注册EndRequest事件,并实现事件处理方法
               class TestModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.EndRequest += new EventHandler(context_EndRequest);
                    }
                    void context_EndRequest(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        ha.Response.Write("--这是每个页面都会动态生成的文字。--grayworm--");
                    }
                } 
            第四步:在Web.Conofig中注册一下这个HttpModule模块
          <httpModules>
           <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"
></add>
          </httpModules> 
          name:模块名称,一般是类名
          type:有两部分组成,前半部分是命名空间和类名组成的全名,后半部分是程序集名称,如果类是直接放在App_Code文件夹中,那程序名称是App_Code。
                这样在Web站点是添加该类库的引用后,运行每个页面,会发现其源文件中都会加入“--这是每个页面都会动态生成的文字。--”这句话。同样的方法你也可以在其中加入JS代码。

2、身份检查
            大家在作登录时,登录成功后,一般要把用户名放在Session中保存,在其它每一个页面的Page_Load事件中都检查Session中是否存在用户名,如果不存在就说明用户未登录,就不让其访问其中的内容。
            在比较大的程序中,这种做法实在是太笨拙,因为你几乎要在每一个页面中都加入检测Session的代码,导致难以开发和维护。下面我们看看如何使用HttpModule来减少我们的工作量
            由于在这里我们要用到Session中的内容,我们只能在AcquireRequestState和PreRequestHandlerExecute事 件中编写代码,因为在HttpModule中只有这两事件中可以访问Session。这里我们选择PreRequestHandlerExecute事件 编写代码。
            第一步:创建一个类库ClassLibrary831。
            第二步:编写一个类实现IHttpModule接口
                class TestModule:IHttpModule
                {
                    public void Dispose()
                    {
                    }
                    public void Init(HttpApplication context)
                    {
                    }
                } 
            第三步:在Init事件中注册PreRequestHandlerExecute事件,并实现事件处理方法
               class AuthenticModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
                    }
                    void context_PreRequestHandlerExecute(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        string path = ha.Context.Request.Url.ToString();
                        int n = path.ToLower().IndexOf("Login.aspx"); 
                        if (n == -1) //是否是登录页面,不是登录页面的话则进入{}
                        {
                            if (ha.Context.Session["user"] == null) //是否Session中有用户名,若是空的话,转向登录页。
                            {
                                ha.Context.Response.Redirect("Login.aspx?source=" + path);
                            }
                        }
                    }
                } 
            第四步:在Login.aspx页面的“登录”按钮中加入下面代码
                protected void Button1_Click(object sender, EventArgs e)
                {
                    if(true)    //判断用户名密码是否正确
                    { 
                        if (Request.QueryString["source"] != null)
                        {
                            string s = Request.QueryString["source"].ToLower().ToString();   //取出从哪个页面转来的
                            Session["user"] = txtUID.Text;
                            Response.Redirect(s); //转到用户想去的页面
                        }
                        else
                        {
                            Response.Redirect("main.aspx");    //默认转向main.aspx
                        }
                    } 
                } 
            第五步:在Web.Conofig中注册一下这个HttpModule模块
          <httpModules>
           <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
          </httpModules>

IHttpModule与IHttpHandler的区别整理的更多相关文章

  1. scanf,fscanf,sscanf的区别----整理

    转自原文 scanf,fscanf,sscanf的区别----整理 scanf 从控制台输入 fscanf 从文件输入 sscanf 从指定字符串输入 1.例:使用scanf函数输入数据. #incl ...

  2. Asp.net的生命周期应用之IHttpModule和IHttpHandler

    摘自:http://www.cnblogs.com/JimmyZhang/archive/2007/11/25/971878.html 从 Http 请求处理流程 一文的最后的一幅图中可以看到,在Ht ...

  3. iOS 和Android客户端测试区别整理ing

    区别很多,慢慢发现整理,注重细节,避免遗漏 消息推送区别: 1.推送渠道: 1.1 iOS走iOS自带的渠道进行系统内推送,应用内和应用外推送无明显差别,均可以收到push信息. 1.2 安卓由于谷歌 ...

  4. (知识)width、naturalWidth、clientWidth、offsetWidth区别整理

    今天在做图片裁剪功能的时候,参考了下网友的资料,发现大家对图片宽度的获取方式不尽相同,于是详细整理下各个属性的区别(详细请参考MDN). 1,HTMLImageElement.width是一个unsi ...

  5. VS中Debug和Realease、及静态库和动态库的区别整理(转)

    原文出自:http://www.cnblogs.com/chensu/p/5632486.html 一.Debug和Realease区别产生的原因 Debug 通常称为调试版本,它包含调试信息,并且不 ...

  6. mysql中DATETIME,DATE和TIMESTAMP的区别整理

    简而言之.看格式,DATE 是 年月日YYYY-MM-DD,DATETIME 是 年月日时分秒YYYY-MM-DD HH:MM:SS,TIMESTAMP是 年月日时分秒YYYY-MM-DD HH:MM ...

  7. VS中Debug和Realease、及静态库和动态库的区别整理

    一.Debug和Realease区别产生的原因 Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序.Release 称为发布版本,它往往是进行了各种优化,使得程序在代码 ...

  8. (转) 寄存器、RAM、ROM、Flash相关概念区别整理

    转自 http://m.blog.chinaunix.net/uid-30077524-id-5570244.html 文章对这几个东西讲得很清楚,值得收藏. 寄存器 寄存器是中央处理器内的组成部份. ...

  9. out 和 ref 之间的区别整理

    ref和out都是C#中的关键字,所实现的功能也差不多,都是指定一个参数按照引用传递. 对于编译后的程序而言,它们之间没有任何区别,也就是说它们只有语法区别. 总结起来,他们有如下语法区别: 1.re ...

随机推荐

  1. C++临时对象销毁时间

    下面这段代码会输出什么? const char* p = string("hello temprary string").c_str(); cout << p; 下面这 ...

  2. poj3006---素数筛法

    #include <stdio.h> #include <stdlib.h> ];//以后都用宏定义 MAX int main()//如要将包括1000000在内的打表,数组就 ...

  3. poj1477---搭积木

    #include<stdio.h> #include<stdlib.h> int main() { int n,i; int bricks[55],set=0; while(s ...

  4. leetcode_question_111 Minimum Depth of Binary Tree

    Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...

  5. C++ Primer 学习笔记_85_模板与泛型编程 --模板特化[续]

    模板与泛型编程 --模板特化[续] 三.特化成员而不特化类 除了特化整个模板之外,还能够仅仅特化push和pop成员.我们将特化push成员以复制字符数组,而且特化pop成员以释放该副本使用的内存: ...

  6. JAVA装饰器模式

    Java程序员们应该对java.io对不会陌生,因为java.io包采用了装饰器模式. 一.定义: Decorator装饰器,顾名思义,就是动态地给一个对象添加一些额外的职责,就好比为房子进行装修一样 ...

  7. datatable赋值行

    datatable复制行:DataTable dt = "";  //这里是填充DataTable数据(""中为一个为datatable类型的值,赋值给dt)D ...

  8. Oracle错误ORA-03113: end-of-file on communication channel处理办法

    oracle不能启动了,报错ORA-03113: end-of-file on communication channel (通信通道的文件结尾) 解决办法: SQL> startup ORAC ...

  9. NOIP第二次模拟赛 stage1【划分数列(seq.pas/c/cpp)

    7划分数列(seq.pas/c/cpp) [题目描述] 给你一个有n个元素的数列,要求把它划分成k段,使每段元素和的最大值最小 [输入格式] 第一行两个正整数n,k 第二行为此数列ai [输出格式] ...

  10. C++中,new/delete和malloc/free的区别

    1.new/delete是C++的操作符,而malloc/free是C中的函数. 2.new做两件事,一是分配内存,二是调用类的构造函数:同样,delete会调用类的析构函数和释放内存.而malloc ...