为你的网站定制一套统一的异常处理机制
写过程序的人都知道,再好的程序都可能存在未能处理的异常情况,因为程序运行的环境和人员的操作方式可以说是千差万别,开发人员在一开始很难把所有的情况都想到,并做相应的处理。所以,开发人员才需要配合测试人员进行协同工作,目的就是尽量较少和消灭(完全消灭当然只是理想情况了)程序中的错误,处理尽可能多的异常情况。在各种应用程序中,网站面临的挑战可以说是各类程序中比较大的了。为什么这么说呢?原因很简单,一个网站的用户千差万别,用户习惯各不相同,用户所使用的电脑和软件平台也各异,网络环境更是大相径庭,所以网站发生异常情况的几率也是比较大的。既然异常不可避免,但我们应该为我们的网站制定一套异常处理机制,即如何更合理的为已经发生的异常善后。本文的讨论仅限于.NET环境的网站开发中的异常处理,其他平台的道理应该是一样的,只是具体的实现方式不同而已。
其实大部分异常无非分为两大类,第一类是你知道可能会发生的,即开发人员在写程序的时候就已经知道可能会发生的一些意外情况。这种情况的异常又可以分为如下几种情况:其一,异常的发生不会影响程序的正常执行,只需要把这个异常正确捕获到,并做相应的处理即可;其二,异常一旦发生,程序无法完成正常的处理逻辑,这个时候需要跳转异常处理逻辑上来,提示或者通知管理员或者最终用户目前发生的情况。以便管理员或者用户做相应的处理以后才能正常执行程序逻辑。举个例子,用户想查询数据库中的某条数据记录,当程序试图连接目标数据库的时候发现数据库服务器Down机了,正常的查询操作已经没有办法继续。这就要求程序在处理像连接数据库这样的操作的时候,先要判断数据库是否运行正常,一旦捕获到数据库运行异常,应该立即记录错误日志并报告数据库管理员,同时给予用户友好的提示;其三,有的异常是正常处理逻辑的需要。比如.NET中Thread.Abort()就会引发一个ThreadAbortException,调用Response.End(), Response.Redirect(), Response.Transfer()的时候也会引发一个ThreadAbortException,这些都是用于控制正常逻辑的。这类异常一般不需要你做太多额外的处理。值得注意的是:我们在写自己的程序的时候,尽量不要把异常当成正常处理逻辑的一部分,这样会导致程序执行效率低下。举个例子:
try
{
temp = Int32.Parse(input);
}
catch
{
temp = 1; // 1是默认值
}
上面这段代码就把异常处理当成了正常处理逻辑的一部分,这样会使得程序执行效率低下。上面这段代码写成如下形式会好些:
if(Int32.TryParse(input, out temp) == false)
{
temp = 1; // 1是默认值
}
现在接着上面的说,除去第一类异常外,还有一种异常即第二类异常是程序开发人员在一开始没有想到的一些异常情况,已经超出了程序编写人员的处理范围。这类异常是很致命的,一旦发生,对系统将造成很大影响。因为到了这个时候,程序已经的运行已经不在我们的控制范围内了。
对于第一类异常,程序员基本都已经将他们就地解决了。对于第二类异常,就需要为其建立一个统一的处理机制。对于一个中等规模以上的网站来说,业务逻辑是比较复杂的,涉及的网页也很多。我们事先不知道哪个页面或者哪段程序会出异常(至少在程序开发的时候没有完全想到的一些异常),所以才需要有这样一套统一的异常处理机制。这里讨论两种可行的办法,第一种办法是为网站所有的页面创建一个基类,基类继承自System.Web.UI.Page,在基类里面统一处理各类异常情况。实现方式是为基类添加一个异常处理事件,即this.Error += new System.EventHandler(this.PageBase_Error); 把你的异常处理逻辑实现在方法PageBase_Error中。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
上面的异常处理方法主要干了两件事情:第一,记录详细的出错信息,包括错误描述,时间,发生的程序集,堆栈跟踪,甚至当前使用网页的用户信息,IP地址等信息。同时给管理员发送邮件。第二,给用户显示一个非常友好的错误提示信息,让用户心里好受些。一旦完成这个基类设计以后,你只要让你的其他所有页面都从这个基类继承下来,就能保证整个网站都有一个统一的异常处理机制了。
第二种统一处理机制的实现方式是,在Global. asax里面实现。开发过.NET网站的朋友应该对他非常熟悉,在里面你可以为整个站点定义各种事件的处理方法,比如SessionStart, ApplicationStart等等。这里我们关注的是站点级的异常处理事件Application_Error(Object sender, EventArgs e),当网站遇到异常的时候,甚至是像404这样的错误,都会触发这个事件。实现方式如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
当然你可以这样来实现:
// 在Global中
{
Server.Transfer("Errors.aspx");
}
// 在Error.aspx中
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
提示:这就尽量避免Error.aspx中再抛出异常。
上面所述的两种处理方式道理都差不多,只是具体实现的方式不同而已。开发者可以根据自己的需要来实现。但个人认为第二种方式稍微好些,因为第二种方式是整个站点级别的异常处理方式,捕获异常的能力更加Powerful,几乎网站所有未能处理的异常都能在这里得到捕获和处理。
其他文章导读: