一:引言

我查阅过不少Asp.Net的书籍,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net。他们耐心、细致地告诉你如何一步步拖放控件、设置控件属性、编写CodeBehind代码,以实现某个特定的功能。

这种做法,实际上是回答了“如何去做”的问题,却没有回答“为什么可以这样做”的问题。

当你按“如何去做”所讲解的内容去开发程序的时候,对于你的用户,你仍是一名程序员;但对于实现了MembershipProvider 和 RoleProvider 抽象类的微软开发人员来说,你已经成了他们的一个用户。

NOTE:我既不反对一些作者只讲解“如何去做”,也不反对你只学“如何去做”,这样也有它的好处,就是可以快速开发。我只是建议多掌握一点底层知识,对一些问题会有更好的理解。

希望通过这一系列文章的讲解,可以让你更好的理解Asp.Net的运作原理和做以了解。

二:Http请求处理流程概述

思考“为什么在地址栏输入www.baidu.com就可以打开百度的网页?”,类似于思考“为什么苹果是往地上掉不是往天上飘?”。对于普通访问者来说,这就像每天太阳东边升起西边落下一样是理所当然的;对于很多程序员来说,认为这个与己无关,不过是系统管理员或者网管员的责任。毕竟,IIS是 Windows 的一个组件,又不是 Asp.Net 的一个组成部分。而实际上,从你轻拍回车到页面呈现在你眼前的十分之一秒内,IIS和.Net Framework已经做了大量的幕后工作。

你可能觉得了解这些幕后工作是如何运作的无关紧要,作为程序员的你只要保证开发出的程序可以高效地运行就可以了。然而,在开发过程中,你却发现常常需要使用诸如 HttpContext 这样的类。这个时候,你可曾思考过这些类的构成和类的实体是如何创建的?你可能简单地回答:HttpContext代表当前请求的一个上下文环境。可你又知道IIS 、Framework、Asp.Net 是如何协同工作处理每个Http请求、如何区分不同的请求、IIS、Framework、Asp.Net三者之间的数据如何流动么?

回答上面这些问题,首先需要了解IIS是如何处理页面请求的,这也是理解 Form验证模式和Windows 验证模式 的基础。http请求处理流程的流程图如下:

或者:

三:Http请求刚刚到达服务器的时候

当服务器接收到一个 Http请求的时候,IIS 首先需要决定如何去处理这个请求(NOTE:服务器处理一个.htm页面和一个.aspx页面肯定是不一样的么)。那IIS依据什么去处理呢?―― 根据文件的后缀名。

服务器获取所请求的页面(NOTE:也可以是文件,比如 test.jpg)的后缀名以后,接下来会在服务器端寻找可以处理这类后缀名的应用程序,如果IIS找不到可以处理此类文件的应用程序,并且这个文件也没有受到服务器端的保护(NOTE:一个受保护的例子就是 App_Code中的文件,一个不受保护的例子就是你的js脚本),那么IIS将直接把这个文件返还给客户端。

能够处理各种后缀名的应用程序,通常被称为 ISAPI 应用程序(NOTE:Internet Server Application Programe Interface,互联网服务器应用程序接口)。虽然这 ISAPI 听上去还挺气派,也算是“应用程序”呢,但仔细看看它的全称就明白了:它实际上只是一个接口,起到一个代理的作用,它的主要工作是映射所请求的页面(文件)  和与此后缀名相对应的实际的处理程序。

让我们更进一步地看一下 ISAPI ,看看它到底是什么样子,请按下面的步骤进行:

  1. 打开IIS。
  2. 选择随意一个站点。
  3. 右边会看到“处理程序映射”
  4. 双击打开。

你应该会看到如下的画面:

图1. 应用程序配置

很清楚地就可以看到,所有IIS所能处理,或者叫 ISAPI 所提供代理服务的 文件类型 及其相对应的实际的后台处理程序都在这里清楚地列出来了。

我们找到 .aspx 的应用处理程序,然后点“编辑”,会出现下面的画面:

图2. 编辑.aspx文件的处理程序

一路看到这里,可以看出,所有的.aspx文件实际上都是由 aspnet_isapi.dll 这个程序来处理的,当IIS把对于.aspx页面的请求提交给了aspnet_isapi.dll以后,它就不再关心这个请求随后是如何处理的了。现在我们应该知道:Asp.Net 只是服务器(IIS)的一个组成部分而已,它是一个 ISAPI扩展。

这里需要注意两点:

  • 当你修改“限制为”后,可以限制页面(文件)只能以某种特定方式访问
  • “确认文件是否存在”是实现 URL 地址映射的关键选项,我以后会专门讲述。

四:理解宿主环境(Hosting)

从本质上讲,Asp.Net 主要是由一系列的类组成,这些类的主要目的就是将Http请求转变为对客户端的响应。HttpRuntime类是Asp.Net的一个主要入口,它有一个称作 ProcessRequest 的方法,这个方法以一个 HttpWorkerRequest 类作为参数。HttpRuntime 类几乎包含着关于单个 Http请求的所有信息:所请求的文件、服务器端变量、QueryString、Http 头信息 等等。Asp.Net 使用这些信息来加载、运行正确的文件,并且将这个请求转换到输出流中,

一般来说,也就是HTML页面。

NOTE:二般来说,也可以是张图片。

当 Web.config文件的内容发生改变 或者 .aspx文件发生变动的时候,为了能够卸载运行在同一个进程中的应用程序(NOTE:卸载也是为了重新加载),Http请求被分放在相互隔离的应用程序域中。

NOTE:可能你以前就听过应用程序域,但是不了解怎么回事,应用程序域就是 AppDomain。

对于IIS来说,它依赖一个叫做 HTTP.SYS 的内置驱动程序来监听来自外部的 HTTP请求。在操作系统启动的时候,IIS首先在HTTP.SYS中注册自己的虚拟路径。

NOTE:实际上相当于告诉HTTP.SYS哪些URL是可以访问的,哪些是不可以访问的。举个简单的例子:为什么你访问不存在的文件会出现 404 错误呢?就是在这一步确定的。

如果请求的是一个可访问的URL,HTTP.SYS会将这个请求交给 IIS 工作者进程。

NOTE:IIS6.0中叫做 w3wp.exe,IIS5.0中叫做 aspnet_wp.exe。

每个工作者进程都有一个身份标识 以及 一系列的可选性能参数。

NOTE:可选性能参数,是指诸如 回收机制的设置、超时时间设置 等等。

接下来进行的事情就是上一章节讲述的 ISAPI 了。

NOTE:这部分的内容相关性比较强,为了让大家好理解,我最后还是决定把 ISAPI 放到前面了,可能全系列完成的时候会再调整吧。

除了映射文件与其对应的处理程序以外,ISAPI 还需要做一些其他的工作:

  1. 从HTTP.SYS中获取当前的Httq请求信息,并且将这些信息保存到 HttpWorkerRequest 类中。
  2. 在相互隔离的应用程序域AppDomain中加载HttpRuntime。
  3. 调用 HttpRuntime的ProcessRequest方法。

接下来才是程序员通常编写的代码所完成的工作了,然后,IIS 接收返回的数据流,并重新返还给 HTTP.SYS,最后,HTTP.SYS 再将这些数据返回给客户端浏览器。

OK,现在你看到张子阳的空间主页了。

图3.Asp.Net 的宿主环境

五:理解管道(Pipeline)

在前面两章中,我们在一个相对比较低的层次上讨论了从发出Http请求到看到浏览器输出这转瞬即逝的十分之一秒内IIS和 Framework 所做的事情。但是我们忽略了一个细节:程序员编写的代码是如何在这一过程中衔接的,本章我们就来看看这个问题。

当Http请求进入 Asp.Net Runtime以后,它的管道由托管模块(NOTE:Managed Modules)和处理程序(NOTE:Handlers)组成,并且由管道来处理这个 Http请求。

图4. 理解 Http 管道

我们按编号来看一下这幅图中的数据是如何流动的。

1. HttpRuntime将Http请求转交给 HttpApplication,HttpApplication代表着程序员创建的Web应用程序。HttpApplication创建针对此Http请求的 HttpContext对象,这些对象包含了关于此请求的诸多其他对象,主要是HttpRequest、HttpResponse、HttpSessionState等。这些对象在程序中可以通过Page类或者Context类进行访问。、

2. 接下来Http请求通过一系列Module,这些Module对Http请求具有完全的控制权。这些Module可以做一些执行某个实际工作前的事情

3. Http请求经过所有的Module之后,它会被HttpHandler处理。在这一步,执行实际的一些操作,通常也就是.aspx页面所完成的业务逻辑。可能你会觉得在创建.aspx页面并没有体会到这一过程,但是,你一定知道,.aspx 页面继承自Page类,我们看一下Page类的签名:

public class Page : TemplateControl, IHttpHandler{
    // 代码省略
}

可以看到,Page类实现了IHttpHandler接口,HttpHandler也是Http请求处理的最底层。

4.HttpHandler处理完以后,Http请求再一次回到Module,此时Module可以做一些某个工作已经完成了之后的事情。

NOTE:注意我用红色标识的字,然后回想一下:Asp.Net 中是不是有众多的 Inserting 、Inserted 之类成对的事件?其实,这里讲述的就是为什么Asp.Net可以将一个Insert操作分成前后两部分,然后再分别进行事件拦截的幕后原理。

如果我们将注意力只集中在Http请求、HttpHandler和HttpModule上,不去考虑HttpContext和HttpApplication,那么图4.可以简化成下面这样:

图5.Http请求在HttpHandler 和 HttpModule 中的流动方向

六:Asp.net管道

  从请求进入ASP.NET工作者进程,直至它到达最终的处理程序之前要经过一系列的步骤和过程,这个步骤和过程称为ASP.NET处理管道。

  Asp.net的处理管道流程如下:

  

  语言描述如下:

  1. Asp.net处理管道的第一步是创建HttpWorkerRequest对象,它包含于当前请求有关的所有信息。
  2. HttpWorkerRequest把请求传递给HttpRuntime类的静态ProcessRequest方法。HttpRuntime首先要做的事是创建HttpContext对象,并用HttpWorkerRequest进行初始化。
  3. 创建了HttpContext实例之后,HttpRuntime类就通过调用HttpApplicationFactory的静态GetApplicationInstance()方法,为该应用程序请求HttpApplication派生类的一个示例。GetApplicationInstance()方法要么创建一个HttpApplication类的一个新实例,要么从应用程序对象池中取出一个实例。
  4. 在创建完成HttpApplication实例之后,就对它进行初始化,并在初始化期间分配应用程序定义的所
  5. 有模块。模块式实现IHttpModule接口的类,作用就是为了实现那经典的19个标准处理事件。
  6. 在创建了模块之后,HttpRuntime类通过调用它的BeginProcessRequest方法,要求最新检索到的HttpApplication类对当前请求提供服务。然后,为当前请求找到合适的处理程序工厂。
  7. 创建处理程序,传递当前HttpContext,一旦ProcessRequest方法返回,请求完成。

具体可以通过反编译代码来看,从入口HttpRuntime的ProcessRequest来看:

总结

本文中,我首先概要介绍了这系列文章将要为大家讲述的主题。然后,我提出了部分程序员存在的一个问题:在一个比较高的层次上学习和使用Asp.Net。

随后,我以一个访问百度的例子,引出了本文主要讲述的三个内容:

  1. Http请求刚刚到达时IIS时,IIS 所做的工作。
  2. Http请求的宿主环境。
  3. Http管道。
  4. asp.net的管道

Asp.Net构架(Http请求处理流程)的更多相关文章

  1. Asp.Net构架(Http请求处理流程)、(Http Handler 介绍)、(HttpModule 介绍)

    Asp.Net构架(Http请求处理流程) Http请求处理流程概述 对于普通访问者来说,这就像每天太阳东边升起西边落下一样是理所当然的:对于很多程序员来说,认为这个与己无关,不过是系统管理员或者网管 ...

  2. Asp.Net构架(Http请求处理流程) - Part.1

    引言 我查阅过不少Asp.Net的书籍,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net.他们耐心.细致地告诉你如何一步步拖放控件.设置控件属性.编写CodeBehind代码,以实现某个特定 ...

  3. Asp.Net构架(Http请求处理流程)、Asp.Net 构架(Http Handler 介绍)、Asp.Net 构架(HttpModule 介绍)

    转载: HttpHaddler,HttpModule http://blog.csdn.net/jiuqiyuliang/article/details/18713451 http://www.cnb ...

  4. ASP.NET MVC的请求处理流程

    (1)用户打开浏览器,在地址栏输入某个网址URL并回车,浏览器便开始向该URL指向的服务器发送HTTP请求(一般是GET方式).(2)服务器端的网站服务系统(IIS)接收到该请求,先检查自己是否认识该 ...

  5. ASP.NET的MVC请求处理流程

    1.用户打开浏览器,在地址栏输入某个网址的URL并回车,浏览器便开始像该URL指定的服务器发起HTTP请求 .2.服务器的网站服务系统(IIS)接收到该请求,先检查自己是否认识该类请求,如果认识就直接 ...

  6. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

  7. ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程

    好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人>: --> 开篇:上一篇 ...

  8. 【转载】ASP.NET页面运行机制以及请求处理流程

    本文转至 ASP.NET页面运行机制以及请求处理流程 IIS处理页面的运行机制 IIS自身是不能处理像ASPX扩展名这样的页面,只能直接请求像HTML这样的静态文件,之所以能处理ASPX这样扩展名的页 ...

  9. ASP.Net MVC请求处理流程

    ASP.Net MVC请求处理流程 好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人& ...

随机推荐

  1. maxima已知方程,计算结果

  2. hekaiming专坑

    先挖个 图像去雾之何凯明暗通道先验去雾算法原理及c++代码实现 ICCV 2017:FAIR Mask R-CNN ICCV 2017:FAIR 密集物体检测的 Focal Loss one-stag ...

  3. LeetCode 100. Same Tree相同的树 (C++)

    题目: Given two binary trees, write a function to check if they are the same or not. Two binary trees ...

  4. Leetcode61.旋转链表

    链表中的点已经相连,一次旋转操作意味着: 先将链表闭合成环 找到相应的位置断开这个环,确定新的链表头和链表尾 class Solution{ public: ListNode* rotateRight ...

  5. gradle-在一个模块中引入其它模块

    现在有两个项目pet-api和pet-provider,这两个项目都在pet-parent当中,项目结构如下: 现在要在pet-provider中调用pet-api 先在parent中的setting ...

  6. c# 多线程多个参数

    for (int i = 0; i <count; i++) //根据选择的串口号数量创建对应数量的线程 { thread = new Thread(new ParameterizedThrea ...

  7. Debian 9 部分快捷键失效问题

    教程 具体修复过程: 安装gnome-screensaver包,重启恢复正常.

  8. [RN] react-native FlatList 实现列表选中的最佳方式(刷新指定Item)

    效果如下: 核心思路就是往数据源里面 给每条数据加一个选中状态. 如图在网络请求完成之后,给每条数据添加一个select的状态: data.list.forEach(item => item.s ...

  9. [LeetCode] 12. Integer to Roman 整数转化成罗马数字

    Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. Symbol Value I 1 ...

  10. .NET Core:跨域

    在Startup中的ConfigureServices方法中配置:services.AddCors(options => options.AddPolicy("any", b ...