服务器处理动态页面原理-1
昨天写的浏览器向服务器请求页面的原理,主要是讲了关于请求静态页面的,今天讲讲服务器处理动态页面
今天用一般处理程序(.ashx)来讲解,一般处理程序是asp.net的核心。
一般处理程序(HttpHandler): 是一个实现System.Web.IHttpHandler特殊接口的类。 能够作为一个外部请求的目标程序的前提是必须实现了IHttpHandler接口。(凡是没有实现此接口的类,就不能被浏览器请求。)
接昨天写的:
IIS发现请求的页面是动态页面,一看自己处理不了,于是就把该请求转交给了IIS的可扩展程序aspnet_isapi.exe,该扩展程序又交给了.NetFrameWork,.net内部处理是通过ISAPIRuntime等一系列操作实现的,首先创建ISAPIRuntime的对象,而后调用自己的ProcessRequest方法来处理请求:
第一步:在ProcessRequst中创建ISAPIWorkerRequest 并且讲ISAPIWorkerRequest 作为参数传给了HttpRuntime的ProcessRequestNoDemand方法
public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IRegisteredObject
{
public int ProcessRequest(IntPtr ecb, int iWRType)
{
...........
ISAPIWorkerRequest wr = null;
try
{
bool useOOP = iWRType == 1;
wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);//通过调用静态方法CreateWorkerRequest创建ISAPIWorkerRequest wr.Initialize();
........................
if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
{
HttpRuntime.ProcessRequestNoDemand(wr);
return 0;
}
..............
}
catch (Exception exception)
{
..........
}
}
}第二步:接下来有是什么呢,我么来看看ProcessRequestNoDemand(wr)这个方法:
internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)
{
RequestQueue queue = _theRuntime._requestQueue;//拿到了一个请求队列
wr.UpdateInitialCounters();
if (queue != null)
{
wr = queue.GetRequestToExecute(wr);//哇,在这里才是正的创建出了HttpWorkerRequest,这里可是包含有请求上下文啊
}
if (wr != null)
{
CalculateWaitTimeAndUpdatePerfCounter(wr);
wr.ResetStartTime();
ProcessRequestNow(wr);//嗯?怎么wr怎么又被传出去了,接下来再看看这个方法有干了写什么
}
}第三步:接这查看一下ProcessRequestNow(wr)方法:
internal static void ProcessRequestNow(HttpWorkerRequest wr)
{
_theRuntime.ProcessRequestInternal(wr);//又是作为参数来传了,继续看看这个ProcessRequestInternal(wr)又干什么了
}第四步:ProcessRequestInternal(wr)查看:
private void ProcessRequestInternal(HttpWorkerRequest wr)
{
HttpContext context;
try
{
context = new HttpContext(wr, false);//是不是很熟悉这个东东啊
}
catch
{
wr.SendStatus(400, "Bad Request");//生成状态响应码是通过调用的wr对象生成的,因此我们知道Response.Write()方法发回状态码,是通过wr来操作的
wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");
byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
wr.SendResponseFromMemory(bytes, bytes.Length);
wr.FlushResponse(true);
wr.EndOfRequest();
return;}
wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, context);
Interlocked.Increment(ref this._activeRequestCount);
HostingEnvironment.IncrementBusyCount();
try
{…………………//省略
context.Response.InitResponseWriter();//上下文创建好后,就立即初始化Response.Writer
IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);//在这里创建了HttpApplication,只不过是用IHttpHandler接收罢了
if (applicationInstance == null)
{
throw new HttpException(SR.GetString("Unable_create_app_object"));
}
…………………//省略}
catch (Exception exception)
{
…………………//省略}
}第五步:InitResponseWriter();
internal void InitResponseWriter() { if (this._httpWriter == null) {this._httpWriter= newHttpWriter(this);//如果当前的HttpWriter为空就立即new一个出来 this._writer= this._httpWriter;//并且将它赋给了_writer ,注意_writer 它的类型可不是HttpWriter了,而是TextWriter} }至此经过这么多的调用最终还是为了创建HttpContext和HttpApplication啊!
总结一下流程:
1、扩展程序 从 接口拿到请求报文
2、处理请求报文,封装生成wr
3、调用HttpRuntime方法中的pr方法(wr为参数),创建上下文对象HttpContext对象
4、初始化HttpResponse对象(目的是创建HtmlWrite)
5、创建HttpApplication对象(调用HttpApplication中的 pr方法,HttpContext为参数)(实 际上是 通过工厂创建HttpApplicationFactory.GetApplicationInstance(context))
未完,待续……………