写过程序的人都知道,再好的程序都可能存在未能处理的异常情况,因为程序运行的环境和人员的操作方式可以说是千差万别,开发人员在一开始很难把所有的情况都想到,并做相应的处理。所以,开发人员才需要配合测试人员进行协同工作,目的就是尽量较少和消灭(完全消灭当然只是理想情况了)程序中的错误,处理尽可能多的异常情况。在各种应用程序中,网站面临的挑战可以说是各类程序中比较大的了。为什么这么说呢?原因很简单,一个网站的用户千差万别,用户习惯各不相同,用户所使用的电脑和软件平台也各异,网络环境更是大相径庭,所以网站发生异常情况的几率也是比较大的。既然异常不可避免,但我们应该为我们的网站制定一套异常处理机制,即如何更合理的为已经发生的异常善后。本文的讨论仅限于.NET环境的网站开发中的异常处理,其他平台的道理应该是一样的,只是具体的实现方式不同而已。
其实大部分异常无非分为两大类,第一类是你知道可能会发生的,即开发人员在写程序的时候就已经知道可能会发生的一些意外情况。这种情况的异常又可以分为如下几种情况:其一,异常的发生不会影响程序的正常执行,只需要把这个异常正确捕获到,并做相应的处理即可;其二,异常一旦发生,程序无法完成正常的处理逻辑,这个时候需要跳转异常处理逻辑上来,提示或者通知管理员或者最终用户目前发生的情况。以便管理员或者用户做相应的处理以后才能正常执行程序逻辑。举个例子,用户想查询数据库中的某条数据记录,当程序试图连接目标数据库的时候发现数据库服务器Down机了,正常的查询操作已经没有办法继续。这就要求程序在处理像连接数据库这样的操作的时候,先要判断数据库是否运行正常,一旦捕获到数据库运行异常,应该立即记录错误日志并报告数据库管理员,同时给予用户友好的提示;其三,有的异常是正常处理逻辑的需要。比如.NET中Thread.Abort()就会引发一个ThreadAbortException,调用Response.End(), Response.Redirect(), Response.Transfer()的时候也会引发一个ThreadAbortException,这些都是用于控制正常逻辑的。这类异常一般不需要你做太多额外的处理。值得注意的是:我们在写自己的程序的时候,尽量不要把异常当成正常处理逻辑的一部分,这样会导致程序执行效率低下。举个例子:
int temp = 0;
try
{
temp = Int32.Parse(input);
}
catch
{
temp = 1; // 1是默认值
}
上面这段代码就把异常处理当成了正常处理逻辑的一部分,这样会使得程序执行效率低下。上面这段代码写成如下形式会好些:
int temp = 0;
if(Int32.TryParse(input, out temp) == false)
{
temp = 1; // 1是默认值
}
现在接着上面的说,除去第一类异常外,还有一种异常即第二类异常是程序开发人员在一开始没有想到的一些异常情况,已经超出了程序编写人员的处理范围。这类异常是很致命的,一旦发生,对系统将造成很大影响。因为到了这个时候,程序已经的运行已经不在我们的控制范围内了。
对于第一类异常,程序员基本都已经将他们就地解决了。对于第二类异常,就需要为其建立一个统一的处理机制。对于一个中等规模以上的网站来说,业务逻辑是比较复杂的,涉及的网页也很多。我们事先不知道哪个页面或者哪段程序会出异常(至少在程序开发的时候没有完全想到的一些异常),所以才需要有这样一套统一的异常处理机制。这里讨论两种可行的办法,第一种办法是为网站所有的页面创建一个基类,基类继承自System.Web.UI.Page,在基类里面统一处理各类异常情况。实现方式是为基类添加一个异常处理事件,即this.Error += new System.EventHandler(this.PageBase_Error); 把你的异常处理逻辑实现在方法PageBase_Error中。
protected void PageBase_Error(object sender, System.EventArgs e)
{
Exception currentError = Server.GetLastError();
if (currentError == null)
{
return;
}
LogError(currentError); // 把错误信息写到你的日志列表里面,也可以同时给系统管理员发送一封邮件。
string friendlyMsg = "你的友好错误提示";
#if DEBUG // 如果程序处于Debug状态,则直接在页面显示具体错误信息,便于调试
friendlyMsg = currentError.Message + “<br />Stack: ” + currentError. StackTrace;
#endif
// 下面的信息是显示给用户的友好提示信息
Response.Write(friendlyMsg); // 你也可以重定向到某个错误提示页面。这里要小心一点的是,确保你的错误提示页面绝对不要有个Bug,否则可能会形成死循环。所以,错误提示页面最好就是一张完全静态的HTML页面。
Server.ClearError();
}