微软提供的一系列Web控件,固然用着很方便。但它的效率如何?它的原理是什么?为什么很多人都说ASP.NET开发的网站很慢?等等问题都是值得我们研究的。从一个牛人的文章中看到过这么一句话“一个合格的ASP.NET开发人员必须懂得如何不用控件(指Web控件)开发”。不错,学了这么长时间开发,一直没离开过那些用着很“舒适”控件。最近,从网上找资料学习(进行中)了HttpHandler、模板引擎、aspx和WebForm、ASP.NET MVC,以便能深入了解ASP.NET的原理,解开自己心中的那些疑惑。这里先介绍HttpHandler,其它东西之后会在之后的博客中介绍。
(1)HttpHandler的作用
首先要明白浏览器与服务器请求-处理-响应的交互方式(看下图),当然HttpHandler(一般处理程序)扮演的即是服务器处理者的角色:
(2)下面简单介绍http协议及报文:
协议
Ø 连接(Connection):浏览器和服务器之间传输数据的通道。一般请求完毕就关闭,不保持连接,或称为短连接。这样的优点是可以增强服务器处理的客户端并发请求数;缺点是会降低服务器处理速度,因为建立连接的速度很慢。
Ø 请求(Request):浏览器向服务器发送的请求信息,包含请求的类型、数据、浏览器(客户端)的信息(语言、浏览器版本、IP地址)等。
Ø 响应(Response):服务器处理浏览器请求后返回的数据,包含请求是否成功、错误码等。
报文(以IE浏览器请求“百度首页”为例)
Ø 请求(Request):
如下图为百度首页的请求数据报(请求方式为Get时请求传递的数据(参数等)都会在下图的请求标头中(此时请求正文为空),为Post时数据会转到请求正文中。
Get/HTTP/1.1表示向服务器用GET方式请求page,使用Http1.1协议。
Accept-Language表示浏览器支持的语言种类。
Referer:为(图片、js、css文件等)来源页面、所属页面。
Ø 响应(Response):
响应码:“200”OK 表示请求响应成功;
“302”:Found表示重定向,Response.Redirect()使浏览器再请求一次重定向的地址,重定向请求方式为Get。
“404”:Not Found表示未找到所请求页面。
“500”:表示服务器内部出现错误
Content-Type:text/html:表示返回数据的类型,服务器通过此属性告诉客户端响应的数据的类型,这样浏览器就根据返回数据的类型来进行不同的处理,如果是图片类型(image/gif)就显示,如果是文本类型(text/plain)就直接显示纯文本代码等等。这就是为什么要在一般处理程序中设置ContentType属性(例:context.Response.ContentType = "text/html";)
(3)HttpHandler代码演示
Test1
先看一个最简单的HttpHandler:
public class TestHandler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//将ContentType = "text/plain";改为“text/html”
context.Response.ContentType = "text/html";
//接受两个参数name、age
string name = context.Request["name"];
int age = Convert.ToInt32(context.Request["age"]);
//返回给浏览器一句话
context.Response.Write("Hello" + name + " 您的年龄是:" + age);
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
运行这个一般处理程序,然后“手动”给浏览器地址栏的地址添加两个参数,例如:
这样即可运行处结果:Hello zhipeng您的年龄是24。
Test2
由于手动添加参数很麻烦,且容易出错,所以用Html表单(form)自动给服务器提交参数。于是将上例中的一般处理程序保持不变,然后添加一个html页,代码如下:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form action="TestHandler1.ashx" method="post">
姓名:<input type="text" name="name" /><br />
年龄:<input type="text" name="age" /><br />
<input type="submit" value="提交" name="haha" />
</form>
</body>
</html>
步骤:
Ø 首先添加<form></form>标签,因为只有它内部的东西才可能提交给服务器(一般处理程序),然后设置它的action和method属性。分别指明提交给哪个HttpHandler和提交方式
Ø 然后需要设定html页中表单元素的name属性,这里注意,id(不可重复)主要是给js操作dom用的,name(可以重复)才是提交给服务器用的。
Ø 然后服务器端(一般处理程序)就可用context.Request[“username”]来根据name属性来获得提交的属性。
注意:
Ø 将用户填写的内容提交的服务器有如下条件:只有三类标签input、textare、select;只有value值会被提交;标签必须设定name属性;标签必须放到form标签内。
Ø get(默认值)通过url传递表单值,传递数量有限,不传输大量或敏感的数据;post传递的表单值隐藏到http报文中,url中看不到,传递数量无限制。下图为分别为get和post时的报文:
get时,请求标头中含有请求时发送的数据;请求正文为空:
post时,请求时发送的数据从标头字符串中,转移到请求正文中:
Test3
下面做一个简单的小例子,如下图,如果用户名和密码都为admin时,则页面提示"恭喜,登录成功!",否则提示"用户名或密码有错误!"。
较特殊的地方是将所有的代码都放到HttpHandler中,代码如下:
public class TestHandler2 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
//取出请求中的参数username和password
string userName = context.Request["username"];
string passWord = context.Request.QueryString["password"];
//定义画表单page的字符串
string html = "<html><head></head><body><form action='TestHandler2.ashx'>用户名:<input type='text' name='username' value='{username}'/><br/>密 码:<input type='password' name='password' value='{password}' /> <input type='submit' value='登录'/></form><p>{msg}</p></body></html>";
//判断,如果username和password为空则将字符串html中的占位符{username}、{password}、{msg}分别替换为空,然后将字符串返回给浏览器进行解析
if (string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(passWord))
{
string code = html.Replace("{username}", "");
code = code.Replace("{password}", "");
code = code.Replace("{msg}", "");
//将字符串返回给浏览器
context.Response.Write(code);
}
else
{
//如果用户名、密码都正确则将字符串“恭喜,登录成功!”返回给浏览器
if (userName == "admin" && passWord == "admin")
{
context.Response.Write("恭喜,登录成功!");
}
//如果用户名或密码填写不正确,则将填写的信息填充标签的值,并将占位符{msg}替换为“用户名或密码有错误”进行提示
else
{
string code = html.Replace("{username}", userName);
code = code.Replace("{password}", passWord);
code = code.Replace("{msg}", "用户名或密码有错误!");
context.Response.Write(code);
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
其实上例中的字符串html就是一个表单模板,可以真对不同的情况,对该模板进行不同的处理(上例采用的字符串替换方式),但是这种方式不利于美工的修改,且难实现复杂的业务逻辑。为此引出了“模板引擎”的概念,模板引擎的作用、优势以及强大功能会在下篇文章介绍。
(4)总结
控件不是洪水猛兽,学懂了如何不脱控件进行.NET开发,了解它本质的东西,然后开发时就可以根据不同的需求多一种选择方向。