在HttpRuntime创建了HttpContext对象之后,HttpRuntime将随后创建一个用于处理请求的对象,这个对象的类型为HttpApplication。
HttpRuntime管理一个定义在System.Web命名空间下的HttpApplicationFactory类的时候,HttpApplicationFactory通过工厂模式管理HttpApplication对象。在HttpApplicationFactory内部维护了一个HttpApplication对象池,使得被创建的HttpApplication对象可以被重复使用。但是,每一个HttpApplication对象每一次仅仅用于处理一个请求,这样就不需要考虑HttpApplication中多个请求并发的处理问题了。
在HttpApplication中,利用.Net中的事件机制,通过在处理过程中依次发出的多个事件,将这个处理过程分解为多个步骤,这个处理机制通常我们称为处理管道。
处理管道,就是处理复杂问题的时候,将处理的过程分解为多个处理步骤,我们将这种经过多个步骤的处理方式称为处理管道。在.Net中,借助于事件的强大威力,我们可以通过处理管道将复杂的处理步骤封装起来,通过事件将处理过程的多个步骤暴露给程序员,以便于程序员对管理管道进行扩展。
HttpApplication处理管道示意图:
但是,对于一个有着众多事件的类来说,定义大量的事件意味着创建对象的时候需要付出创建事件的成本,定义多个事件,意味着在创建的对象中将会需要更多的存储空间。System.ComponentModel.Component类中,提供了处理多个事件的基础:Events属性,它的类型为System.ComponentModel.EventHandlerList,这是一个线性的字段,当需要事件的时候,就通过key将事件保存到集合中,没有对应的事件,就不会付出创建事件的成本,这样,通过EventHandlerList可以在一个集合中管理多个事件对象,节省了事件对象占用的空间。
1、System.ComponentModel.EventHandlerList
该类的常用成员:
成员定义 | 说明 |
void AddHandler() | 将一个委托加入到集合中,key为委托所对应事件的对象 |
void RemoveHandler() | 删除一个委托 |
Delegate this[Object key] | 通过表示事件的Key取得对应的委托 |
这个类在使用的时候很简单,首先从Component派生一个类,这个类继承Component的Events集合属性。对于这个派生类所需要定义的每一个事件,在类中定义一个对应的作为key的对象,以后,通过这个key对象来访问有Events集合管理的事件。当然,用一个类似字典的集合也能够完成这个任务。
下面试试这个类如何用:
namespace ComponentListTest { class Program { static void Main(string[] args) { //这里是Asp.net程序员写的代码,对于程序员而言,只需要写处理事件就可以了 ProcessPipeline process = new ProcessPipeline(); process.StartProcess += new EventHandler(process_StartProcess); process.EndProcess += new EventHandler(process_EndProcess); process.Process(); Console.ReadKey(); } static void process_StartProcess(object sender, EventArgs e) { Console.WriteLine("开始事件执行"); } static void process_EndProcess(object sender, EventArgs e) { Console.WriteLine("结束事件执行"); } } public class ProcessPipeline : System.ComponentModel.Component { private static readonly object startEvent = new object(); private static readonly object endEvent = new object(); public event EventHandler StartProcess { add { this.Events.AddHandler(startEvent, value); } remove { this.Events.RemoveHandler(startEvent, value); } } public event EventHandler EndProcess { add { this.Events.AddHandler(endEvent, value); } remove { this.Events.RemoveHandler(endEvent, value); } } protected void OnStartProcess(EventArgs e) { if (this.Events[startEvent] != null) { (this.Events[startEvent] as EventHandler)(this, e); } } protected void OnEndProcess(EventArgs e) { if (this.Events[endEvent] != null) { (this.Events[endEvent] as EventHandler)(this, e); } } public void Process() { Console.WriteLine("事件开始顺序执行!"); this.OnStartProcess(EventArgs.Empty); this.OnEndProcess(EventArgs.Empty); } } }
HttpApplication对象是Asp.net中处理请求的重要对象,但是,这种类型的对象实例不是由程序员来创建,而是由Asp.net帮助我们创建。为了便于扩展处理,Asp.net暴露了大量的事件给程序员,这些事件按照固定的处理顺序依次触发,程序员通过编写事件处理方法就可以自定义每一个请求的扩展处理过程。
HttpApplication的19个标准事件如下:
事件名称 | 说明 |
BeginRequest | Asp.net处理的第一个事件,表示处理的开始 |
AuthenticateRequest | 验证请求,一般用来取得请求用户的信息 |
PostAuthenticateRequest | 已经获取请求用户的信息 |
AuthorizeRequest | 授权,一般用来检查用户的请求是否获得权限 |
PostAuthorizeRequest | 用户请求已经得到授权 |
ResolveRequestCache | 获取以前处理缓存的处理结果,如果以前缓存过,那么,不必再进行请求的处理工作,直接返回缓存结果 |
PostResolveRequestCache | 已经完成缓存的获取操作 |
PostMapRequestHandler | 已经根据用户的请求,创建了处理请求的处理器对象 |
AcquireRequestState | 取得请求的状态,一般用于Session |
PostAcquireRequestState | 已经取得了Session |
PreRequestHandlerExecute | 准备执行处理程序 |
PostRequestHandlerExecute | 已经执行了处理程序 |
ReleaseRequestState | 释放请求的状态 |
PostReleaseRequestState | 已经释放了请求的状态 |
UpdateRequestCache | 更新缓存 |
PostUpdateRequestCache | 已经更新了缓存 |
LogRequest | 请求的日志操作 |
PostLogRequest | 已经完成了请求的日志操作 |
EndRequest | 本次请求处理完成 |
2、事件简要介绍
Asp.net服务器对于每一次请求的处理过程都相同,都要经过这个HttpApplication处理管道。管道内部的处理过程是固定的,在服务器处理请求的各个阶段,伴随着处理的进行,依次触发对应的事件,以便于程序员在处理的各个阶段完成自定义的处理工作。
1、最先触发的事件是BeginRequest,这个事件标志着Asp.net服务器处理工作得开始,也是程序员在Asp.net中针对请求所能够处理的第一个事件。
2、开始处理请求后,第一个重要工作就是确定请求用户的身份以实现安全机制,这个工作通过AuthenticateRequest和PostAuthenticateRequest两个事件提供检查当前请求用户身份的机会。检查后的用户可以通过HttpContext的User属性获取到。如:
if (HttpContext.Current.User.Identity.IsAuthenticated) { string UserName = HttpContext.Current.User.Identity.Name; }
3、获取用户身份之后,将开始检查权限的工作。如果没有通过安全检查,一般情况下,都跳过剩下的事件,直接出发EndRequest事件,结束请求的处理过程。
4、当用户通过了权限检查,为了最快获得结果,Asp.net将进行缓存检查,看看是否可以从以前的缓存中直接取得处理的结果。
5、当不能从缓存中获取结果的时候,必须通过一次处理来计算出当前请求的结果。在Asp.net中,用于 处理请求以得到结果的对象称为处理程序Handler,在Asp.net中提供了许多的处理程序,程序员也 可以自定义处理程序。为了处理这个请求,Asp.net必须按照匹配规则找到一个处理当前请求的处理 程序,PostMapRequestHandler事件表示Asp.net已经获取了这个处理程序,HttpContext的Handler 属性就表示这个处理程序对象。从上面的分析可以看到,HttpContext的Handler属性到这里才有实 际的意义。
6、虽然有了处理程序对象,但是还不能立即开始处理,因为会话状态还未获取,还需要先获取Session然后才能获取事件处理程序。
PreRequestHandlerExecute通知程序员,马上开始调用处理程序了,有什么没有准备好的赶紧准备。
7、调用处理程序。
8、在处理程序完成之后,服务器开始进行扫尾工作,PostRequestHandlerExecute事件通知程序员,Asp.net服务器的处理程序已经完成。在处理完成之后,由于在处理程序中,用户可能修改了用户特定的专属数据,那么修改之后的用户状态数据可能需要进行序列化或者进行保存处理。ReleaseRequestState事件通知程序员需要释放这些状态数据,PostReleaseRequestState则表示已经释放完成。
9、在处理完成之后,如果希望将这次处理的结果缓存起来,以便在后继的请求中可以直接使用这个结果,UpdateRequestCache事件提供了处理的机会,PostUpdateRequestCache则表示缓存已经更新完成。
10、在Asp.net 4.0之后,新增加了两个时间完成处理的日志工作:LogRequest表示将这次请求记入日志中,PostLogRequest表示完成了日志工作。
EndRequest是所有请求都要经过的最后一个HttpApplication处理管道的事件,也是程序员处理Asp.net处理请求中的最后一个机会。这个事件之后,处理的结果将被回应道浏览器,完成Asp.net服务器的处理工作。
HttpContext通过属性User和Handler传递了当前请求的用户和处理请求所使用的处理程序信息。如果我们还需要从HttpApplication前面的事件向后面的事件处理程序传递一些参数,那么可以通过HttpContext的Items属性来完成。
HttpContext类中定义了一个Items属性,这是一个字典,定义如下:
public IDictionary Items{ get; }
由于HttpContext对象贯穿整个HttpApplication的处理过程,所以,可以借助于这个属性,从处理过程的前面的步骤中,将数据传递给后面的处理步骤,而不需要通过方法的参数或者对象的成员,这种传递参数的方式称为基于HttpContext的状态管理。
这种状态管理方式是Asp.net中周期最短的状态管理方式,因此有着极高的内存使用效率,但是仅仅能够用在服务器端的一次处理过程中。
HttpApplication提供了基于事件的扩展机制,允许程序员借助于处理管道中的事件进行处理过程扩展。由于HttpApplication对象是由Asp.net基础架构来创建和维护的,那么,如何才能获取这个对象的引用,以便于注册HttpApplication对象的事件处理,在Asp.net中,提供了两种方式来解决这个问题:IHttpModule方式和golbal.asax方式。这两种方式的核心都是IHttpModule接口。
1、通过IHttpModule创建HttpApplication的事件处理程序
在Asp.net中,创建在System.Web命名空间下的IHttpModule接口专门用来定义HttpApplication对象的事件处理。实现IHttpModule接口的类称为HttpModule(Http模块)。
IHttpModule接口的定义如下,其中仅仅包含两个成员:
public interface IHttpModule { void Dispose(); void Init(HttpApplication context) }
其中,Dispose方法用于回收Module所使用的非托管资源,如果没有的话,直接返回即可。
最重要的是Init方法,可以看到,这个方法接收一个HttpApplication类型的参数,在Asp.net中,每当创建一个HttpApplication对象实例,将遍历注册的HttpModule类型,通过反射,依次每个注册HttpModule类型的一个实例对象,并将这个HttpApplication实例通过Init方法传递给各个HttpModule,这样HttpModule就可以在第一时间完成针对HttpApplication对象的事件注册了。
例如:希望写一个处理PostAuthenticateRequest事件的HttpModule,那么可以完成如下事件的注册:
public void Init(System.Web.HttpApplication application) { application.PostAuthenticateRequest += new EventHandler(Application_PostAuthenticateRequest); }
2、注册HttpModule
在Asp.net中,实现IHttpModule接口只是实现HttpModule的第一步,在Asp.net中所使用的HttpModule还必须在网站配置文件中进行注册才能真正生效,并在Asp.net中使用。
配置文件有3个级别,详细可在配置文件系列中找到:http://www.cnblogs.com/kissdodog/category/468516.html
下面以web.config示例进行说明如何注册HttpModule:
system.web配置元素的子元素httpModules用来配置网站所使用的HttpModule;httpModules的子元素add用来增加一个新的HttpModule;clear将清除前面注册的所有HttpModule。
add元素有两个必选的属性name和type,简介如下:
对于IIS7.0来说,需要在配置文件的system.webServer配置节中注册HttpModule。注意此时的配置元素名称变为了modules。在IIS7.0中,可以为MapRequestHandler,LogRequest和PostLogRequest事件添加处理程序。
只要在IIS7.0集成模式下运行并且与.Net Framework3.0或更高版本一起运行的应用程序,才可以支持这些事件。
<system.webServer> <modules> <add name="ModuleExample" type="Samples.ModeleExample"> </modules> </system.webServer>
3、非配置文件的方式注册HttpModule
在Asp.net4.0中,可以不修改配置文件也能达到完成Moudle注册的目的。从.Net 3.5开始,新提供的PreApplicationStartMethodAttribute特征可以应用在程序集上,使得自定义的网站初始化代码可以在Web应用程序的Application_Start初始化环节之前就执行。这个步骤甚至在动态编译和执行Application_Start之前。对于每个程序集,可以定义一次。特征的定义如下:
[AttributeUsageAttribute(AttributeTargets.Assembly,AllowMultiple = false)] public sealed class PreApplicationStartMethodAttribute:Attribute { public Type Type{ get; } public string MethodName{ get; } ... }
Type用来指定定义了初始化方法的类型,MethodName用来指定将要执行的初始化方法。
这样,可以不在配置文件中固定配置HttpModule,而是定义一个方法,这个方法可以返回需要动态注册的HttpModule,将这个方法以委托的形式登记在一个集合中。在网站启动之后,每当HttpApplicationFactory创建一个HttpApplication对象,完成正常注册的HttpModule创建及初始化之后,再来创建我们动态注册的这些HttpModule。
.
.
.
.
.
暂时忽略这些东东,先写下面的
4、常见的HttpModule
在Asp.net中,已经预定义了许多HttpModule,甚至已经在服务器的网站配置文件中进行了注册,在系统文件夹C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config中看到已经注册的HttpModule如下:
<httpModules> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" /> <add name="Session" type="System.Web.SessionState.SessionStateModule" /> <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" /> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" /> <add name="RoleManager" type="System.Web.Security.RoleManagerModule" /> <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" /> <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" /> <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" /> <add name="Profile" type="System.Web.Profile.ProfileModule" /> <add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" /> <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </httpModules>
主要的HttpModule的解释如下:
1、OutputCacheModule完成Asp.net的输出缓存管理工作:
OutputCacheModule的配置参数通过system.web配置元素的caching子元素的outputCache元素进行定义。当启用输出缓存之后(启用还是通过配置文件,下同),OutputCacheModule将注册HttpApplication的ResolveRequestCache和UpdateRequestCache两个事件完成输出缓存的管理。
2、SessionStateModule完成Session的管理工作:
这个Module的配置参数通过配置文件中的system.web配置元素的sessionState子元素进行配置。当启用Session状态管理之后,SessionStateModule将注册HttpApplication的AcquireRequestState、ReleaseRequestState、EndRequest三个事件完成Session状态的管理工作。
3、ProfileModule提供个性化数据管理:
这是一个自定义的类似于Session的会话状态管理,但是,个性化数据的读取和保存可以由程序员完全控制,并且提供了强类型的数据访问方式。这个Module的配置参数在system.web的子元素profile中进行说明。当启用了个性化数据管理之后,Module将注册HttpApplication的AcquireRequestState和EndRequest事件处理。
4、AnonymousIdentificationModule提供匿名用户的标志:
是否启用匿名用户标志在配置文件的system.web配置元素的子元素anonymousIdentification中定义,还可以配置匿名标识的管理方式。由于在AuthenticateRequest事件中将验证用户,获取用户名,所以这个Module注册了PostAuthenticateRequest的事件处理,当用户没有经过验证的时候,为用户分配一个唯一的匿名标识。
5、WindowsAuthenticationModule、FormsAuthenticationModule和PassportAuthenticationModule用来完成用户的验证工作。
它们通过配置文件中system.web的子元素authentication子元素定义,mode属性用来指定网站当前使用的验证方式,也就是哪一个Module将被用来完成验证工作。在启用验证的情况下,FormsAuthenticationModule和PassportAuthenticationModule将注册HttpApplication的AuthenticateRequest和EndRequest事件进行用户的验证处理。WindowsAuthenticationModule将注册AuthenticateRequest的事件处理。
6、RoleManagerModule、UrlAuthorizationModule、FileAuthorizationModule用来完成用户的授权管理:
授权管理的配置参数来自system.web的authorization子元素。UrlAuthorizationModule和FileAuthorizationModule注册了HttpApplication的AuthorizeRequest事件处理,用来检查Url和文件的访问授权。RoleManagerModule在Url和文件访问授权检查通过之后,通过用户的标识和角色来完成用户的授权检查,RoleManagerModule注册了HttpApplication的PostAuthenticateRequest和EndRequest事件处理。
5、HttpModule事件
每个HttpModule也可以触发自定义的事件,但是,处理这些HttpModule事件更加麻烦一些,因为这些HttpModule对象实例也不是我们自己创建的。
一般情况下,通过HttpApplication的Modules属性获取特定的HttpModule,这个属性的定义如下:
public HttpModuleCollection Modules{ get; }
可以使用定义HttpModule时候的name作为索引来获取对应的HttpModule。例如,获取前面定义的HttpModule对象的引用:
application.Modules["online"]
然后就可以定义这个HttpModule的事件处理了。
6、通过global.asax创建HttpApplication的事件处理程序
在Visual Studio中创建的Asp.net项目中的Global.asax代码如下:
public class Global : System.Web.HttpApplication { void Application_Start(object sender, EventArgs e) { // 在应用程序启动时运行的代码 } void Application_End(object sender, EventArgs e) { // 在应用程序关闭时运行的代码 } void Application_Error(object sender, EventArgs e) { // 在出现未处理的错误时运行的代码 } void Session_Start(object sender, EventArgs e) { // 在新会话启动时运行的代码 } void Session_End(object sender, EventArgs e) { // 在会话结束时运行的代码。 // 注意: 只有在 Web.config 文件中的 sessionstate 模式设置为 // InProc 时,才会引发 Session_End 事件。如果会话模式设置为 StateServer // 或 SQLServer,则不会引发该事件。 } }
下面给出一个HttpModule捕捉异常的示例,在Application:
protected void Application_Error() { var error = Server.GetLastError(); var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500; //如果不是HttpException记录错误信息 if (code != 404) { //此处邮件或日志记录错误信息 } Response.Write("出错"); Server.ClearError(); string path = Request.Path; Context.RewritePath(string.Format("~/Errors/Http{0}", code), false); IHttpHandler httpHandler = new MvcHttpHandler(); httpHandler.ProcessRequest(Context); Context.RewritePath(path, false); }
这样,就不用把try{}catch{}写得整个系统都是了!
7、global.asax中HttpApplication事件的自动注册
在global.asax中,针对HttpApplication的事件处理,可以通过定义特殊命名的方法来实现。首先,这些方法必须符合System.EventHandler,因为所有的HttpApplication管道事件都使用这个委托定义。第二,方法的作用域必须是public。第三,方法的命名格式必须如下:Application_注册的事件名称。按照这种命名方法定义在global.asax中的方法将被自动注册到对应的事件中。
例如,希望在global.asax中注册PostAuthenticateRequest事件处理,那么在global.asax中应该定义一个如下的方法:
void Application_PostAuthenticateRequest(object sender, EventArgs e) { Response.Write("验证通过事件!"); }
这对所有请求都有效,来看效果:
8、特殊的HttpApplication事件处理
通过global.asax文件,可以简单地完成一些特殊的事件处理,只要按照特定的命名形式,就可以使定义的方法自动注册到对应的事件中。在Asp.net中,有些事件甚至只能通过global.asax来完成处理。
1、Start事件
这个不是HttpApplication处理管道中的事件,当网站启动后,第一次请求到达网站之后,Asp.net网站将首先触发一次这个事件,而且在网站的整个生命周期中,也仅仅触发一次。由System.Web.HttpApplicationFactory对象触发,所以,也不能通过HttpApplication对象来获取相关的请求参数。在这个事件处罚的时候,第一次请求的上下文对象HttpContext也已经创建,所以,可以通过HttpContext.Current获取第一次的上下文请求对象,然后通过这个上下文对象来获取相关信息。
由于这个事件在网站第一次请求的时候触发,所以非常适合针对网站全局的数据进行初始化工作,在Asp.net MVC中,RouteTablle就是在这个事件中创建的。
2、End事件
当网站应用程序被关闭的时候,将触发这个事件。
3、Error事件
当网站应用程序出现错误,或者处理过程中出现未捕获的异常时,HttpApplication将抛出这个事件 。
这个事件的事件源是HttpApplication,当前的异常信息可以通过HttpApplication的Server属性获取HttpServerUtility的对象实例来完成。HttpServerUtility对象的GetLasError()方法将返回最后一次的异常,这个方法的定义如下:
public Exception GetLastError();
这个异常是一个经过包装的异常,它的InnerException属性指向网站最后一次抛出的未处异常。
常见的处理如下:
void Application_Error(object sender, EventArgs e) { HttpServerUtility server = (sender as HttpApplication).Server; Exception exception = server.GetLastError().InnerException; //针对异常的处理 Response.Write("异常信息:" + exception.Message); //清理这个异常 server.ClearError(); }
模拟输出一个异常:
protected void Page_Load(object sender, EventArgs e) { throw new Exception("模拟异常"); }
输出如下:
4、Session的Start事件
当Asp.net每次创建了一个新的Session后,换句话说,创建了一个新的SessionID之后,就会触发Session的Start事件。需要注意到,在Asp.net中,支持会话的HttpModule在配置文件中注册的name就是Session。
5、Session的End事件
当一个Session过期之后,或者通过调用Abandon方法被丢弃之后,将会触发Session的End事件。这个事件的事件源实际上是SessionStateModule,而不是HttpApplication。需要注意的是,关闭浏览器不会导致Session的End事件。而且,如果Session的管理模式是StateServer或者SQLServer的话,将不会触发这个事件。
6、HttpModule的事件注册
从Session的处理可以看出,对于注册到网站中的HttpModule,如果这些Module也会抛出事件,而我们希望能够处理这些HttpModule事件的时候,可以在global.asax通过定义如下名称形式的方法来处理HttpModule的事件。
HttpModule注册名称_事件名称
HttpApplication_BeginRequest(BeginRequest是19个事件的名称)。当然,方法必须首先要符合事件的委托定义。
在Asp.net 2.0之后,提供了匿名用户的标识支持,这是通过一个注册名为AnonymousIdentification的HttpModule实现的,它同事提供了一个名为Creating的事件,定义事件的委托如下:
public delegate void AnonymousIdentificationEventHandler(object sender,AnonymousIdentificationEventArgs e)
那么,在global.asax中,可以定义如下命名形式的方法来处理这个事件。
public void AnonymousIdentificaton_Creating(object sender,AnonymousIdentificationEventArgs args) { }
例如个性化数据Profile的事件处理。个性化数据是通过注册名为Profile的HttpModule进行处理的,它的实际类型为ProfileModule,这个类提供了一个名为MigrateAnonymous的合并匿名用户数据的事件,这个事件的委托定义如下:
public delegate void ProfileMigrateEventHandler(object sender,ProfileMigrateEventArgs)
所以,可以在global.asax中定义如下形式的方法进行处理。
public void Profile_OnMigrateAnonymous(object sender,ProfileMigrateEventArgs args) { ProfileCommon anonymousProfile = Profile.GetProfile(args.AnonymousID); ProfileManager.DeleteProfile(args.AnonymousID); AnonymousIdentificationModule.ClearAnonymousIdentifier(); Membership.DeleteUser(args.AnonymousID,true); }
1、PreSendRequestHeaders
当准备通过HttpResponse回应发送HTTP的Header之前,HttpApplication将会触发PreSendRequestHeaders事件。在这个事件中,可以根据发送的Header来动态设置一些参数,比如,如果通过Content-Type参数获知发送的内容是text/html网页,那么,可以通过启用输出的压缩来提高网络的传输速度。这个操作可以通过设置一个特殊的Header来通知浏览器。
2、PreSendRequestContent
当准备通过HttpResponse回应发送HTTP的Body内容之前,HttpApplication将会触发PreSendRequestContent事件。如果配置了输出到客户端的压缩,那么可以在这个事件中包装输出到浏览器的流以实现输出的压缩。
HttpApplication处理对象与HttpModule处理模块 (第三篇),布布扣,bubuko.com
HttpApplication处理对象与HttpModule处理模块 (第三篇)
原文:http://www.cnblogs.com/mingxuantongxue/p/3822544.html