微软提供的一系列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开发,了解它本质的东西,然后开发时就可以根据不同的需求多一种选择方向。