ASP.NET管道模型简析
我相信在第一次听到这个名词时,有的小伙伴会一脸懵,而且还有很多疑问,其实我在第一次接触这个概念时跟很多小伙伴一样一脸懵.
接下来我将以我自己的理解来讲述什么是管道模型。
什么是管道模型
首先有没有小伙伴思考过在.NET 中WebForm、MVC、Webapi 之类的框架做应用程序的开发部署之后,用户在浏览器或是利用HttpClient 输入URL地址请求之后是怎么到达我们的应用程序呢?中间又经过了哪些步骤呢?
其实在用户输入URL之后,Http请求会经过一系列的流转,每次流转都有一些特有的处理,而管道模型就是为Http请求提供支撑和流转而抽象出的一个模型。
在实际中他是如何执行的
老规矩先上图,然后再一步一步分析,这样比较直观,其实在isapi之前还有一些只是在流程图中没有标记出来,因为没必要去深究,至少在目前阶段.
下面以文字的方式来解释一下,管道模型一部分的流程图走向情况:
用户发起请求到达DNS,DNS会解析域名找到对应的IP及端口。
IIS中HttpSys监听服务接受请求。
HttpSys监听服务根据请求类型的后缀,将请求转发到对应的应用程序处理(isapi.dll),IIS中处理程序映射可以实现配置,不同的后缀将到达不同的处理程序.net的请求映射到aspnet.isapi,java或者其他的也可以配置对应的dll。
在http请求到达Isapi后会将请求转换为一个HttpWorkerRequest对象,然后把对象传入到
HttpRuntime.ProcessRequest在ProcessRequest方法中利用HttpApplicationFactory传入HttpContext进行构建
HttpApplication,当然在这前几个步骤如果发生错误,那就直接返回了。
我上面描述的这一部分已经执行完了,当然由于是系统固定流程这时作为开发者并不能进行升级或者是扩展,待请求到达了我们被创建的HttpApplication之后的才是真正的开始.
HttpApplication
HttpApplication类在管道模型中充当一个很重要的角色,它定义对 ASP.NET 应用程序内所有应用程序对象公用的方法、属性和事件,此类是用户在 Global.asax 文件中定义的应用程序的基类,订阅httpApplication事件的任何 HTTP 模块 (HttpModule) 都必须实现 IHttpModule接口.
在我们学习管道的过程中,所注重的应该是它所发布的一系列事件,它们用来处理各式各样的请求,并且每次请求都会将它们逐一执行一遍,但由于处理不尽相同,又可能都需要,所以使用了事件的模式来扩展,具体事件内容和作用,在下方引入的代码中.
开闭原则
观察者模式
(用事件的意义:封装共性部分,将不确定部分利用事件的方式,说白了就是委托回调,将需要扩展的部分以委托的形式暴露出去,委托对于C#,跟指针对于C一样的伟大,一样的令人膜拜)
public class HttpApplication : IComponent,IDisposable,
IHttpAsyncHandler, IHttpHandler,
IRequestCompletedNotifier, ISyncContext
{
//表示处理的开始
public event EventHandler BeginRequest;
//验证请求,一般用来取得请求用户的信息
public event EventHandler AuthenticateRequest;
//已经获取请求用户的信息
public event PostAuthenticateRequest;
// 授权,一般用来检查用户的请求是否获得权限
public event AuthorizeRequest;
//用户请求已经得到授权
public event PostAuthorizeRequest;
//获取以前处理缓存的处理结果,如果以前缓存过,那么不必再进行请求的处理,直接返回缓存结果
public event ResolveRequestCache;
//已经完成缓存的获取操作
public event PostResolveRequestCache;
//已经根据用户的请求,创建了处理请求的处理器对象
public event PostMapRequestHandler;
//取得请求的状态,一般用于Session
public event AcquireRequestState;
//已经取得了Session
public event PostAcquireRequestState;
//准备执行处理程序
public event PreRequestHandlerExecute;
//已经执行了处理程序
public event PostRequestHandlerExecute;
//释放请求的状态
public event ReleaseRequestState;
//已经释放了请求的状态
public event PostReleaseRequestState;
//更新缓存
public event UpdateRequestCache;
// 已经更新了缓存
public event PostUpdateRequestCache;
//请求的日志操作
public event LogRequest;
//已经完成了请求的日志操作
public event PostLogRequest;
本次请求处理完成
public event EndRequest;
}
HttpModule
疑问又来了,既然HttpApplication发布了一系列事件,我想对其发布某个事件进行扩展或者自定义又该如何操作呢?接下来就该HttpModule登场了,没错他才是主角,在ASP.NET中占有举足轻重的地位,可以说是大哥级别的,因为无论是WebForm,又或者是MVC乃至WebAPI都只是HttpModule延伸出来的冰山一角而已,这么说在某种意义上一点也不过分,只是突然感觉自己很渺小.
突然这样说可能让人无法理解,当你自己去理解了,你肯定会赞同我这种说法.
由于每一次Http请求,都会将HttpApplication中所有的事件执行一遍,同理那实现订阅的HttpModule也会针对每一个请求而执行一次,所以比较适合做一些全局的操作,例如缓存,或者实现请求压缩,做一些性能监控,或者恶意ip请求校验,下面用一个实例来实现HttpModule请求压缩,以及实现的步骤
- 1.首先创建一个类GzipModule 实现IHttpModule接口
internal class GzipModule : IHttpModule
{
public void Dispose(){}
public void Init(HttpApplication app)
{
app.BeginRequest += App_BeginRequest;
}
private void App_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
string IsAcceptType = app.Context.Request.Headers["Accept-Encoding"];
//请求头不包含格式编码直接拦截返回
if (string.IsNullOrEmpty(IsAcceptType)) return;
IsAcceptType = IsAcceptType.ToUpperInvariant();
//如果客户端请求头包含压缩请求标识那么响应也返回压缩格式
//如果是默认请求就返回默认的响应格式
if (IsAcceptType.Contains("GZIP"))
{
app.Context.Response.AppendHeader("Content-encoding", "gzip");
app.Context.Response.Filter = new GZipStream(app.Context.Response.Filter
, CompressionMode.Compress);
}
else if (IsAcceptType.Contains("DEFLATE"))
{
app.Context.Response.AppendHeader("Content-encoding", "deflate");
app.Context.Response.Filter = new DeflateStream(app.Context.Response.Filter
, CompressionMode.Compress);
}
}
}
- 2.在配置文件下注册HttpModule
<system.webServer>
<httpErrors existingResponse="PassThrough" />
<modules>
<add name="GzipModule" type="namespace.GzipModule, namespace" preCondition="integratedMode" />
</modules>
</system.webServer>
到这里您可能会问有没有动态注册的方式不写在配置文件,我的回答是有的,以webapi框架为例
1.在AssemblyInfo文件中加入编译特性,在代码编译时动态注册
[assembly: PreApplicationStartMethod(typeof(DynamicRegisterHttpMoudle), "RegisterMoudle")]
public class DynamicRegisterHttpMoudle
{
public static void RegisterMoudle()
{
HttpApplication.RegisterModule(typeof(GzipModule));
}
}
2.利用静态构造函数注入,因为静态构造函数是在类加载时首先被CLR调用的
public class WebApiApplication : System.Web.HttpApplication
{
static WebApiApplication(){
RegisterModule(typeof(GzipModule));
}
protected void Application_Start() { }
}
到这里你可能仍然无法理解HttpModule,只是简单知道它是什么和它的表象,最重要的一点就是任何Http请求都会经过它,但是我觉得知道这一点就够了,相信随着后面的积累,你对它将会对它有颠覆性的认识,并且崇拜它.
HttpHandler
接下来我们还要认识一个重要的内容HttpHandler,至于它是什么?相对正式的回答是这样的:
HttpHandler是一个HTTP请求的真正处理中心,也正是在这个HttpHandler容器中,ASP.NET Framework才真正地对客户端请求的服务器页面做出编译和执行并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。
不过从字面意思还是能看得懂的,至于大白话的意思就是Http最终的请求是由这个叫HttpHandler来完成的,到底是不是这样呢?在后面我会进一步去验证,先来做一个HttpHandler简单的实现,我们自定义一个后缀为.cc请求的被我们自定义的HttpHandler处理。
1.首先自定义类然后继承自IHttpHandler
public class CustomHttpHander : IHttpHandler
{
public bool IsReusable => false;
public void ProcessRequest(HttpContext context)
{
string time =DateTime.Now.ToString();
string respone = string.Format("自定义HttpHander,{0}请求到达", time );
context.Response.Write(respone);
}
}
2.配置文件注册HttpHandler
<system.webServer>
<httpErrors existingResponse="PassThrough" />
<modules>
<add name="CustomHttpHandler" path="*.cc" verb="*" type="namespace.CustomHttpHander,namespace" preCondition="integratedMode,runtimeVersionv4.0" />
</modules>
</system.webServer>
这样我们就自定义了一个.cc后缀的请求被CustomHttpHandler处理,至于为什么能实现特殊请求后缀的自定义,这是HttpHandler的机制,但是它的核心内容还是一个Http请求处理中心,当然我们后续会进一步了解的MvcHandler 、HttpControllerHandler这些meb框架中的核心处理程序,从源码的角度来更进一步的了解它。
至此管道模型大致的概念以及执行流程已经在本文中做了简单分析,后续学习Mvc和Webapi的源码因为和管道这一块衔接很紧密,有了这一部分的铺垫及知识点画像,相对会更加容易理解。
ASP.NET管道模型简析的更多相关文章
- Asp.net管道模型(管线模型)
Asp.net管道模型(管线模型) 前言 为什么我会起这样的一个标题,其实我原本只想了解asp.net的管道模型而已,但在查看资料的时候遇到不明白的地方又横向地查阅了其他相关的资料,而收获比当初预 ...
- Asp.net管道模型(管线模型)之一发不可收拾
前言 为什么我会起这样的一个标题,其实我原本只想了解asp.net的管道模型而已,但在查看资料的时候遇到不明白的地方又横向地查阅了其他相关的资料,而收获比当初预想的大了很多. 有本篇作基础,下面两篇就 ...
- asp.net管道模型
查了很多资料,终于大概弄懂管道模型(注意并非指定是asp.net范畴)是个什么概念了,其实就是从Unix移植过来的一种概念,也可以说是一种模式吧(只允许一头读,一头写,并且读完了就会自动消失). as ...
- ASP.NET-HTTP管道模型
HTTP管道模型处理WEB程序很小的一方面.管道模型是类似于Web Services的一种在服务器端处理ASP.NET页面的框架技术 一.管道对象模型 在System.Web的命名空间中处理HTTP的 ...
- Asp.net管道模型之(HttpModules 和 HttpHandler)
上一节我们从大概范围介绍了管道模型的整体流程,我们从其中知道管道最重要的两大组件为:HttpModules 跟 HttpHandler.今天我们着重来介绍一下这两大组件 一:asp.net处理管道 从 ...
- ASP.Net 管道模型 VS Asp.Net Core 管道 总结
1 管道模型 1 Asp.Net Web Form管道 请求进入Asp.Net工作进程后,由进程创建HttpWorkRequest对象,封装此次请求有关的所有信息,然后进入HttpRuntime类进 ...
- Owin管道与asp.net管道模型
------2016.3.6 更新 文中提到没有Microsoft.Owin.Host.SystemWeb 这个dll 便不会加载Startup.Configuration,因为这个dll 其中有个O ...
- asp.net 管道模型+生命处理周期
http://www.cnblogs.com/qianlifeng/archive/2010/12/16/1908568.html https://msdn.microsoft.com/zh-cn/l ...
- Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)
Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要 ...
随机推荐
- [luogu4331]数字序列
令$a'_{i}=a_{i}+n-i$.$b'_{i}=b_{i}+n-i$,代价仍然是$\sum_{i=1}^{n}|a'_{i}-b'_{i}|$,但条件变为了$b'_{i}\le b'_{i+1 ...
- [atARC098F]Donation
贪心,一定在最后一次经过某节点时付出$b_{u}$,条件是付出后$W\ge \max(a_{i}-b_{i},0)$(同时也可以仅考虑这个限制,因为$W$在过程中不会增大) 假设"最后一次经 ...
- 如何利用 JuiceFS 的性能工具做文件系统分析和调优
JuiceFS 是一款面向云原生环境设计的高性能 POSIX 文件系统,在 AGPL v3.0 开源协议下发布.作为一个云上的分布式文件系统,任何存入 JuiceFS 的数据都会按照一定规则拆分成数据 ...
- mybatis-批量操作数据(list对象 )
在实际工作中老是忘记 传入的参数和数据库参数名称要一致还是与实体类型一致导致很多笑话发生. 那我还是做个记录吧! dao层: int addRemark(@Param("list" ...
- 基于Docker搭建Maven私服Nexus,Nexus详解
备注:首先在linux环境安装Java环境和Docker,私服需要的服务器性能和硬盘存储要高一点,内存不足可能到时启动失败,这里以4核8GLinux服务器做演示 一:基于Docker安装nexus3 ...
- [IIS]文件夹权限
发布完iis,默认的 Application Pool 没有权限访问文件夹. 可以给项目文件夹添加用户权限. 右键 - "属性" - "安全" - " ...
- Codeforces 878D - Magic Breeding(bitset,思维题)
题面传送门 很容易发现一件事情,那就是数组的每一位都是独立的,但由于这题数组长度 \(n\) 很大,我们不能每次修改都枚举每一位更新其对答案的贡献,这样复杂度必炸无疑.但是这题有个显然的突破口,那就是 ...
- 洛谷 P6189 - [NOI Online #1 入门组]跑步(根号分治+背包)
题面传送门 题意: 求有多少个数列 \(x\) 满足: \(\sum x_i=n\) \(x_i\geq x_{i+1}\) 答案对 \(p\) 取模. ...你确定这叫"入门"组 ...
- RNA_seq 热图绘制
若已经拿到表达矩阵exprSet 若差异较大,进行log缩小不同样本的差距 1.热图全体 1 ##加载包 2 library(pheatmap) 3 4 ##缩小表达量差距 5 exprSet < ...
- R语言与医学统计图形-【31】动态交互绘图
1.plotly包 动态散点图 library(plotly) # 交互散点图 plot_ly(data=iris, x=~Sepal.Length, y=~Petal.Length, marker= ...