(转)Asp.Net底层原理(三、Asp.Net请求响应过程)
原文地址:http://www.cnblogs.com/liuhf939/archive/2013/09/16/3324753.html
在之前,我们写了自己的Asp.Net框架,对整个流程有了一个大概的认识。这次我们来看一下Asp.Net整个请求处理过程是怎么样的。
浏览器封装请求报文,发送请求到达服务器,服务器内核模块的HTTP.SYS监听到用户的HTTP请求,将其分发给W3SVC,W3SVC解析出请求的URL,并根据Metabase获取映射关系得到目标应用,如果是静态资源(HTML,jss,img等),则将内容以HTTP响应的车型是返回。如果是动态文件(aspx、ashx)等,则进一步获取到目标对应的工作进程w3wp.exe,如果不存在,则创建一个新的工作进程。工作进程w3wp.exe利用aspnet_isapi.dll创建处理当前请求的应用程序域,随后ISAPIRuntime会被加载,ISAPIRuntime会接管该HTTP请求。
ISAPIRuntime会首先创建一个ISAPIWorkRequest对象,对请求报文进行了简单的封装,并将该ISAPIWorkRequest对象传递给HttpRuntime。
HttpRuntime会根据ISAPIWorkRequest创建用于封装Http请求上下文的对象HttpConetxt。
HttpContext主要包括HttpRequest(当前请求)和HttpResponse(服务器响应)
1 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]
2 public int ProcessRequest(IntPtr ecb, int iWRType)
3 {
4 IntPtr zero = IntPtr.Zero;
5 if (iWRType == 2)
6 {
7 zero = ecb;
8 ecb = UnsafeNativeMethods.GetEcb(zero);
9 }
10 //创建了ISAPIWorkRquest空对象
11 ISAPIWorkerRequest wr = null;
12 try
13 {
14 bool useOOP = iWRType == 1;
15 //通过ecb句柄创建了ISAPIWorkRequest对象
16 wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
17 wr.Initialize();
18 string appPathTranslated = wr.GetAppPathTranslated();
19 string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
20 if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
21 {
22 //IsapiRuntime把WR交给了HttpRuntime
23 HttpRuntime.ProcessRequestNoDemand(wr);
24 return 0;
25 }
26 HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated }));
27 return 1;
28 }
29 catch (Exception exception)
30 {
31 try
32 {
33 WebBaseEvent.RaiseRuntimeError(exception, this);
34 }
35 catch
36 {
37 }
38 if ((wr == null) || !(wr.Ecb == IntPtr.Zero))
39 {
40 throw;
41 }
42 if (zero != IntPtr.Zero)
43 {
44 UnsafeNativeMethods.SetDoneWithSessionCalled(zero);
45 }
46 if (exception is ThreadAbortException)
47 {
48 Thread.ResetAbort();
49 }
50 return 0;
51 }
52 }
53
54
ISAPIRuntime
HttpRuntime通过HttpApplicationFactory获取一个新的或现有的HttpApplication对象。
1 private void ProcessRequestInternal(HttpWorkerRequest wr)
2 {
3 Interlocked.Increment(ref this._activeRequestCount);
4 if (this._disposingHttpRuntime)
5 {
6 try
7 {
8 wr.SendStatus(0x1f7, "Server Too Busy");
9 wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");
10 byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>");
11 wr.SendResponseFromMemory(bytes, bytes.Length);
12 wr.FlushResponse(true);
13 wr.EndOfRequest();
14 }
15 finally
16 {
17 Interlocked.Decrement(ref this._activeRequestCount);
18 }
19 }
20 else
21 {
22 HttpContext context;
23 try
24 {
25 //通过wr创建了上下文对象
26 context = new HttpContext(wr, false);
27 }
28 catch
29 {
30 try
31 {
32 wr.SendStatus(400, "Bad Request");
33 wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");
34 byte[] data = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
35 wr.SendResponseFromMemory(data, data.Length);
36 wr.FlushResponse(true);
37 wr.EndOfRequest();
38 return;
39 }
40 finally
41 {
42 Interlocked.Decrement(ref this._activeRequestCount);
43 }
44 }
45 wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, context);
46 HostingEnvironment.IncrementBusyCount();
47 try
48 {
49 try
50 {
51 this.EnsureFirstRequestInit(context);
52 }
53 catch
54 {
55 if (!context.Request.IsDebuggingRequest)
56 {
57 throw;
58 }
59 }
60 context.Response.InitResponseWriter();
61
62 //通过HttpApplicationFactory获取HttpApplication实例
63 IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
64 if (applicationInstance == null)
65 {
66 throw new HttpException(SR.GetString("Unable_create_app_object"));
67 }
68 if (EtwTrace.IsTraceEnabled(5, 1))
69 {
70 EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, applicationInstance.GetType().FullName, "Start");
71 }
72 if (applicationInstance is IHttpAsyncHandler)
73 {
74 IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
75 context.AsyncAppHandler = handler2;
76
77 //执行HttpApplication的BeginProcessRequest方法
78 handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
79 }
80 else
81 {
82 applicationInstance.ProcessRequest(context);
83 this.FinishRequest(context.WorkerRequest, context, null);
84 }
85 }
86 catch (Exception exception)
87 {
88 context.Response.InitResponseWriter();
89 this.FinishRequest(wr, context, exception);
90 }
91 }
92 }
HttpRuntime
HttpApplication负责处理分发给它的请求。由于一个HttpApplication对象在同一时间只能处理一个请求,只有完成对某个请求的处理后,HttpApplication才能用于后续请求 的处理,所以Asp.Net采用对象池的获取HttpApplication对象。
当第一个请求到达时,HttpApplicationFactory会一次创建多个HttpApplication对象,并将其置于对象池中,选择其中一个对象来处理该请求。处理完毕后HttpApplication不会回收,而是释放到池中。池中空闲的HttpApplication对象用于处理后续请求,当没有空闲的时候再进行创建新的HttpApplication。
HttpApplication对象的创建时根据Global文件编译后的类型,通过反射的方式创建的,很消耗资源和时间,因此这里使用了对象池的技术
1.确保Global文件被编译,如果没有Global文件,则对所有事件提供HttpApplication的默认行为。
Global:它继承自HttpApplication类,用于维护一个HttpApplication对象池,并在需要的时候讲对象池中的对象分配给应用程序。
2.创建一个特殊的HttpApplication对象,并调用它的Application_Start方法。
3.获取一个用于处理当前请求的HttpApplication实例,进行初始化。
1 internal static IHttpHandler GetApplicationInstance(HttpContext context)
2 {
3 if (_customApplication != null)
4 {
5 return _customApplication;
6 }
7 if (context.Request.IsDebuggingRequest)
8 {
9 return new HttpDebugHandler();
10 }
11 _theApplicationFactory.EnsureInited();
12 _theApplicationFactory.EnsureAppStartCalled(context);
13 return _theApplicationFactory.GetNormalApplicationInstance(context);
14 }
初始化:①.创建HttpModuleCollection集合——>根据配置文件,获取所有的HttpModule,并循环执行HttpModule的初始化方法。
1 private void InitModules()
2 {
3 HttpModuleCollection modules = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
4 HttpModuleCollection other = this.CreateDynamicModules();
5 modules.AppendCollection(other);
6 this._moduleCollection = modules;
7 this.InitModulesCommon();
8 }
9
10
11 private void InitModulesCommon()
12 {
13 int count = this._moduleCollection.Count;
14 for (int i = 0; i < count; i++)
15 {
16 this._currentModuleCollectionKey = this._moduleCollection.GetKey(i);
17 this._moduleCollection[i].Init(this);
18 }
19 this._currentModuleCollectionKey = null;
20 this.InitAppLevelCulture();
21 }
②.对HttpApplication的管道事件和HttpHandler有序绑定,主要有两处HttpHandler。
1.——>在管道第7-8个事件之间执行了MapHandlerExecutionStep事件:
判断是否指向了一个具体的HttpHandler实例,如果没有,则根据请求的url创建页面处理程序或一般处理程序。
(为什么要判断是否指向一个具体的HttpHandler呢,MVC请求到达的时候会在第七个事件中,指向一个MvcHandler,而不是创建一般处理程序)
2.——>在管道第11-12个事件之间执行了HttpHandler的ProcessRequest方法:
执行一般处理程序的ProceRequest方法,或者是Page页面的生命周期。
1 internal override void BuildSteps(WaitCallback stepCallback)
2 {
3 ArrayList steps = new ArrayList();
4 HttpApplication app = base._application;
5 bool flag = false;
6 UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
7 flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0);
8 steps.Add(new HttpApplication.ValidateRequestExecutionStep(app));
9 steps.Add(new HttpApplication.ValidatePathExecutionStep(app));
10 if (flag)
11 {
12 steps.Add(new HttpApplication.UrlMappingsExecutionStep(app));
13 }
14 app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
15 app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
16 app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
17 app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
18 app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
19 app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
20 app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
21 app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
22
23 //创建页面对象或一般处理程序
24 steps.Add(new HttpApplication.MapHandlerExecutionStep(app));
25 app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
26 app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
27 app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
28 app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
29 steps.Add(app.CreateImplicitAsyncPreloadExecutionStep());
30
31 //执行一般处理程序的PR方法或开始Page页面的生命周期
32 steps.Add(new HttpApplication.CallHandlerExecutionStep(app));
33 app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
34 app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
35 app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
36 steps.Add(new HttpApplication.CallFilterExecutionStep(app));
37 app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
38 app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
39 this._endRequestStepIndex = steps.Count;
40 app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
41 steps.Add(new HttpApplication.NoopExecutionStep());
42 this._execSteps = new HttpApplication.IExecutionStep[steps.Count];
43 steps.CopyTo(this._execSteps);
44 this._resumeStepsWaitCallback = stepCallback;
45 }
HttpRuntime拿到了HttpApplication对象,HttpRuntime开始触发HttpApplication的请求处理,即调用HttpApplication的BeginProcessRequest方法。
1 IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
2 {
3 this._context = context;
4 this._context.ApplicationInstance = this;
5 this._stepManager.InitRequest();
6 this._context.Root();
7 HttpAsyncResult result = new HttpAsyncResult(cb, extraData);
8 this.AsyncResult = result;
9 if (this._context.TraceIsEnabled)
10 {
11 HttpRuntime.Profile.StartRequest(this._context);
12 }
13 this.ResumeSteps(null);
14 return result;
15 }
16
17
ResumeSteps
其中error = application.ExecuteStep(this._execSteps[this._currentStepIndex], ref completedSynchronously);
便是通过_execSteps来依次执行事件函数的调用。
在所有事件函数被调用完成之后,HttpApplication实例会被回收,ISAPIRuntime.ProcessRequest处理完毕,结果返回给COM,并通过COM的再一次处理,返回给客户端。这样一次请求就至此结束了。
1 [DebuggerStepperBoundary]
2 internal override void ResumeSteps(Exception error)
3 {
4 bool flag = false;
5 bool completedSynchronously = true;
6 HttpApplication application = base._application;
7 CountdownTask applicationInstanceConsumersCounter = application.ApplicationInstanceConsumersCounter;
8 HttpContext context = application.Context;
9 ThreadContext context2 = null;
10 AspNetSynchronizationContextBase syncContext = context.SyncContext;
11 try
12 {
13 if (applicationInstanceConsumersCounter != null)
14 {
15 applicationInstanceConsumersCounter.MarkOperationPending();
16 }
17 using (syncContext.AcquireThreadLock())
18 {
19 try
20 {
21 context2 = application.OnThreadEnter();
22 }
23 catch (Exception exception)
24 {
25 if (error == null)
26 {
27 error = exception;
28 }
29 }
30 try
31 {
32 try
33 {
34 Label_004D:
35 if (syncContext.Error != null)
36 {
37 error = syncContext.Error;
38 syncContext.ClearError();
39 }
40 if (error != null)
41 {
42 application.RecordError(error);
43 error = null;
44 }
45 if (!syncContext.PendingCompletion(this._resumeStepsWaitCallback))
46 {
47 if ((this._currentStepIndex < this._endRequestStepIndex) && ((context.Error != null) || base._requestCompleted))
48 {
49 context.Response.FilterOutput();
50 this._currentStepIndex = this._endRequestStepIndex;
51 }
52 else
53 {
54 this._currentStepIndex++;
55 }
56 if (this._currentStepIndex >= this._execSteps.Length)
57 {
58 flag = true;
59 }
60 else
61 {
62 this._numStepCalls++;
63 syncContext.Enable();
64 error = application.ExecuteStep(this._execSteps[this._currentStepIndex], ref completedSynchronously);
65 if (completedSynchronously)
66 {
67 this._numSyncStepCalls++;
68 goto Label_004D;
69 }
70 }
71 }
72 }
73 finally
74 {
75 if (flag)
76 {
77 context.RaiseOnRequestCompleted();
78 }
79 if (context2 != null)
80 {
81 try
82 {
83 context2.DisassociateFromCurrentThread();
84 }
85 catch
86 {
87 }
88 }
89 }
90 }
91 catch
92 {
93 throw;
94 }
95 }
96 if (flag)
97 {
98 context.RaiseOnPipelineCompleted();
99 context.Unroot();
100 application.AsyncResult.Complete(this._numStepCalls == this._numSyncStepCalls, null, null);
101 application.ReleaseAppInstance();
102 }
103 }
104 finally
105 {
106 if (applicationInstanceConsumersCounter != null)
107 {
108 applicationInstanceConsumersCounter.MarkOperationCompleted();
109 }
110 }
111 }
HttpApplication 管线会依次处理下面的请求:
- 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。
- 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。
- 引发 BeginRequest 事件。
- 引发 AuthenticateRequest 事件。
- 引发 PostAuthenticateRequest 事件。
- 引发 AuthorizeRequest 事件。
- 引发 PostAuthorizeRequest 事件。
- 引发 ResolveRequestCache 事件。
- 引发 PostResolveRequestCache 事件。通知HttpModule根据请求选择对应的HttpHnadler加载至上下文中。
- 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。(除了配置文件中的,还有上下文中的HttpHnadler)
- 引发 PostMapRequestHandler 事件。继续通知HttpModule确定要使用哪个HttpHandler用以处理请求。
- 引发 AcquireRequestState 事件。
- 引发 PostAcquireRequestState 事件。
- 引发 PreRequestHandlerExecute 事件。
- 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 BeginProcessRequest)。例如,如果该请求针对某页,则当前的页实例将处理该请求。
- 引发 PostRequestHandlerExecute 事件。
- 引发 ReleaseRequestState 事件。
- 引发 PostReleaseRequestState 事件。
- 如果定义了 Filter 属性,则执行响应筛选。
- 引发 UpdateRequestCache 事件。
- 引发 PostUpdateRequestCache 事件。
- 引发 EndRequest 事件。
(转)Asp.Net底层原理(三、Asp.Net请求响应过程)的更多相关文章
- Asp.Net请求响应过程
Asp.Net请求响应过程 在之前,我们写了自己的Asp.Net框架,对整个流程有了一个大概的认识.这次我们来看一下Asp.Net整个请求处理过程是怎么样的. 浏览器封装请求报文,发送请求到达服务器, ...
- Spring框架系列(14) - SpringMVC实现原理之DispatcherServlet处理请求的过程
前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet ...
- [置顶] Asp.Net底层原理(一、浏览器和服务器的交互原理)
…… 一.浏览器和服务器的交互原理 二.写自己的"迷你"Asp.net框架 三.Asp.Net的请求与响应过程 1.在此之前,首先简单的模拟一下我们去请求一个网址的时候,浏览器和服 ...
- HTTP协议请求响应过程和HTTPS工作原理
HTTP协议 HTTP协议主要应用是在服务器和客户端之间,客户端接受超文本. 服务器按照一定规则,发送到客户端(一般是浏览器)的传送通信协议.与之类似的还有文件传送协议(file transfer p ...
- [置顶] Asp.Net底层原理(二、写自己的Asp.Net框架)
我们介绍过了浏览器和服务器之间的交互过程,接下来介绍Asp.net处理动态请求. 写自己的Asp.Net框架,我们不会引用System.Web这个程序集,我们只需要创建要给自己的类库,所以在接下来的程 ...
- ASP.NET底层原理
上图基本上演示了IIS 6整个处理过程.在User Mode下,http.sys接收到一个基于aspx的http request,然后它会根据IIS中的Metabase查看该基于该Request的Ap ...
- 基于asp.net MVC 的服务器和客户端的交互(三)之客户端请求响应
一.分析 WEB API 中HTTP 请求方式的四个主要方法 (GET, PUT, POST, DELETE), 按照下列方式映射为 CURD 操作: GET 用于获取 URI 资源的进行展示,GET ...
- [ Laravel 5.5 文档 ] 底层原理 —— 一次 Laravel 请求的生命周期
Posted on 2018年3月5日 by 学院君 简介 当我们使用现实世界中的任何工具时,如果理解了该工具的工作原理,那么用起来就会得心应手,应用开发也是如此.当你理解了开发工具如何工作,用起 ...
- ES 18 - (底层原理) Elasticsearch写入索引数据的过程 以及优化写入过程
目录 1 Lucene操作document的流程 1.1 添加document的流程 1.2 删除document的流程 2 优化写入流程 - 实现近实时搜索 2.1 流程的改进思路 2.2 设置re ...
随机推荐
- FPGA中逻辑复制
copy from http://www.cnblogs.com/linjie-swust/archive/2012/03/27/FPGA_verilog.html 在FPGA设计中经常使用到逻辑复制 ...
- curl -I 说明
curl -I 查看header头信息
- shell编程中变量的运算 (shell 06)
主要包括以下3种 字符串操作数学运算浮点运算 一.字符串操作 字符串的连接 连接字2个字符串不需要任何连接符,挨着写即可 长度获取 expr length "hello" expr ...
- mapred.JobClient: No job jar file set. User classes may not be found. See JobConf(Class) or JobConf#setJar(String).
报错详情: WARN mapred.JobClient: No job jar file set. User classes may not be found. See JobConf(Class) ...
- PL/SQL 训练05--游标
--隐式游标--通过一个简单的SELECT ...INTO 语句提取一行数据,并放在一个局部变量中,最简单获取数据的途径 --显示游标--可以在声明单元明确的声明一个查询,这样可以在一个或多个程序中打 ...
- Android BindService中遇到的一个小问题
今天在使用BindService的时候遇到个小问题,我希望通过Bindservice获取到这个服务,然后执行服务内的某个自定义方法,如下: if(bindService==null){ Intent ...
- Linux - 创建用户的相关文件
创建一个用户会与 6 个文件相关 /etc/passwd 储存了所有用户的相关信息 第一行中,从左往右 root 为用户名,: 为分隔符,x 为密码,0 为 uid,0 为 gid,root 为用户的 ...
- PHP文件操作(三)-文件的写入
fwrite() //对文件进行写入 fwrite(file,string,length)file:必选项,需要写入的文件string:必选项,规定要写入文件的字符串length:可选项,规定要写入 ...
- python web指纹获取加目录扫描加端口扫描加判断robots.txt
前言: 总结上几次的信息收集构造出来的. 0x01: 首先今行web指纹识别,然后在进行robots是否存在.后面是目录扫描 然后到使用nmap命令扫描端口.(nmap模块在windows下使用会报停 ...
- Deep Learning 学习笔记(5):Regularization 规则化
过拟合(overfitting): 实际操作过程中,无论是线性回归还是逻辑回归,其假设函数h(x)都是人为设定的(尽管可以通过实验选择最优). 这样子就可能出线“欠拟合”或者“过拟合”现象. 所谓过拟 ...