客户端向服务器端发送请求,服务器端接收并处理这个请求,返回给客户端。而HTTP协议定义客户端(Web浏览器)和服务器端(Web服务器)通信的机制。
1, HTTP请求
当你将浏览器指向一个URL时,它利用域名服务系统(DNS)将URL提供的服务器名称翻译为一个IP地址。
接下来,浏览器打开一个套接字Socket,连接到该IP地址的80端口。对http://127.0.0.1/Default.aspx下载请求的包具有下面这样简单的形式:
GET /Default.aspx HTTP/1.1
Host: 127.0.0.1
HTTP请求中通常包含许多头信息(Head):
User-Agent:识别发出请求的浏览器类型;
Connection:关闭连接或保持连接;
If-Modified-Since:提供客户端高速缓存验证。
HTTP头信息是一行文本,提供有关请求的其他信息。文本的第一行是该请求的起始含,其中必须包含要执行的HTTP命令(如GET)名称、资源URL,以及目标HTTP协议版本。
觉不觉得跟第二篇文章中的代码段七有点像。另外,在IIS配置里,我们也可以找到关于HTTP头的设置,像“自定义HTTP头“、“MIME类型”等,如下图所示:
2, HTTP响应
服务器的响应包括消息的协议版本和退出代码(说明成功或错误)组成的一个状态行。
状态行的后面为一串头信息(通过为页面内容的类型和长度)和页面内容。
一个空白行将页面内容和其余信息分来,如下所示:
HTTP/1.1 200 OK
Server:Microsoft-IIS / 5.0
Content-Type:text/html
Content-Length:51
<html><body><h1>ASP.NET is cool!</h1></body></html>
上述代码展示了由 Web服务器返回的简单 HTML输出。请求和响应是根据 HTTP架构格式的字符串,通过 TCP连接进行传输。代码为 200表示对此请求的一切处理正常。指定的 Web服务器处理该请求,根据给定的( MIME)类型( text/html)返回和具有一定长度的页面内容。
接下来的处理取决于MIME类型和浏览器的功能。只要MIME类型为text/html,浏览器就将页面内容显示为HTML。
觉不觉得跟第二篇文章中的代码段八有点像。
3, 服务器端抽象层
我们现在知道,客户端请求一个页面,然后服务器端响应这个请求,处理后再发给它。如果请求的是.html页面,就简单了,直接把页面放到数据包传过去就行,但.aspx页面怎么办?不可能直接发给客户端。那么在服务器端必须有一个抽象出来的东西(IIS进程)来完成这个工作。
Web浏览器与Web服务器之间的每次会话都由类似于我们前面所说的数据包交换构成。一般地,如果客户端请求的URL是.html页面,Web服务器读取该文件,将此文件内容刷新到响应的数据包中。如果URL为ASP.NET页面,就用一个专用的IIS模块。该模块是一个ISAPI扩展的IIS插件。一个ISAPI扩展是以文件扩展的方式注册的一个动态连接库(DLL)。任何时候,当某种资源类型的请求进入时,相应的ISAPI扩展将进行处理。
关于ISAPI我们也不陌生。下图IIS配置,.aspx文件对应的动态连接库(DLL)文件为aspnet_isapi.dll,它可以执行的动作有“GET”,“HEAD”,“POST”和“DEBUG”;而.shtm和.shtml文件对应的DLL文件为ssinc.dll,执行的动作只有“GET”和“POST”,显然不能有“DEBUG”。
当请求.aspx文件进入时,注册处理.aspx文件的ISAPI扩展将进行处理。
在配置IIS时,是不是曾经看过如下配置IIS的图。若禁止了“所有未知ISAPI”,IIS将无法识别.aspx文件。
处理.aspx页面的ISAPI扩展首先对在隐藏域(即调用上下文)中来回传送的会话状态进行反序列化处理。该信息用于配置创建页面输出的新实例化的控件。然后,保存在调用上下文与来自客户端控件(如文本框和复选框)的任何新信息进行合并。状态全部恢复后,就允许运行生成HTML输出。
但是处理.aspx文件不是这么简单的。要经过IIS几个进程的处理,这里暂时先不说。
4, 提交窗体
HTML的<form>标记是唯一被授权将客户端数据传输到服务器的元素。当用户单击类型为submit的按钮时,根据设计,浏览器将数据该窗体的所有控件的当前内容填充到一个字符串,然后此字符串作为GET或POST命令的组成部分被传递到服务器。
现在我们在.NET中创建一个.aspx文件,内容如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<input id="Text1" type="text" />
<input id="Submit1" type="submit" value="submit" /></div>
</form>
</body>
</html>
浏览器源文件,内容如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Untitled Page</title>
</head>
<body>
<form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="/wEPDwUJNzgzNDMwNTMzZGT8XigVHlmkk+BXiblfwYUp8bVAIA==" />
</div>
<div>
<input id="Text1" type="text" />
<input id="Submit1" type="submit" value="submit" /></div>
</form>
</body>
</html>
从代码中可见,该窗体与POST命令和Default.aspx这个URL相关联。
POST /Default.aspx HTTP/1.1
Host:127.0.0.1
Content-Type:application/x-www-form-urlencoded
Content-Length:12
Text1=1001
在处理页面请求时,ISAPI扩展解析请求内容,将通过对程序员更友好的对象模型找到的任何信息进行公开。例如,不是继续使用简单的名称/值字符串,而是将Text1变量转移到一个应用程序级的集合,即Request.Form集合。这表示在原始HTTP编程模型上构建的第一级抽象。像Request、Response、Server这类对象组成了HTTP上下文。