异常处理是一项重大任务,设计一个好的策略并不简单。
首先,有一些通用规则:
- 当运行代码无法继续时会发生异常,所以也许它试图处理一些内部异常但最终失败了。想想TCP连接:如果损坏的数据包到达,则为异常,但TCP协议可以处理它。如果有太多数据包损坏,则会抛出I/O或套接字异常。
- 异常并不总是可以被处理。几乎在所有情况下,当您从底层层次收到异常时,就无法运行纠正性代码。如果您的应用程序依赖于离线的DB,并且您得到了关于它的异常,那么您只能显示错误消息。
- 异常可能是意外的,并可能暴露设计或实现缺陷。例如,一个实现缺陷可能是这样一种情况:当您无法连接到第一镜像时,您拥有冗余DB,但不尝试使用第二镜像。
对于第三点,重要的是记录异常并定期分析日志以查找任何奇怪的情况。所以,让我们开始具体回答。
首先
考虑“处理”异常。当您编写每个代码行时,请考虑可能阻止其完成的可能问题,并考虑可能的纠正操作(如果有可能)。错误消息不是好的处理方式,而是最后的策略。
不要开始编写try-catch(Exception),而应该选择特定的异常。如果您需要将字符串解析为数字等,则期望FormatException
,如果您需要从Object
转换为您的类型,则期望InvalidCastException
。
当您编写较低层次的图层时
不要犹豫地抛出异常!!不要像许多人一样做,例如返回null或使用(如ANSI C)布尔返回值和引用参数。异常就是为此而存在的。如果您可以处理异常(例如,您找不到本地文件,但知道您有远程备份,因此通过调用远程镜像来处理FileNotFoundException
,但如果您仍然无法连接,则最终抛出异常),则这样做并尝试恢复计算,但如果您不能,则抛出异常。而且别忘了抛出内部异常,如果存在的话,因为它对于高层日志记录很有帮助。
基本上,即使您没有捕获任何异常,仍然可以决定自己抛出异常!这在函数参数无效时尤其推荐!
另一个好选择是仍然在底层记录。实际上,您想记录无论是否发生异常。
当您记录日志时
记得给消息适当的严重程度。如果你通过代码发现你的数据库离线了,那不是一个意外的异常。仍然将其记录为错误,但在调查日志时不要担心代码错误。相反,如果你捕获到你的代码无法识别的异常(例如NullReferenceException
),则应该使用最高级别(即致命错误)进行记录,以赋予它最高优先级!
ASP.NET的良好策略
可以基于Page.OnError
方法。如果你为站点的所有页面都有一个基础页面类,那么你应该绝对重写该方法。在该方法中,你应该首先记录你的异常。
你也不应滥用try-catch(Exception)块,因为如果你无法处理catch中的异常,你必须通过OnError来处理它。
当你运行这样的方法时,不要立即考虑Server.RemoveError()
。你可以选择为HTTP 500错误设置静态HTML页面(当未处理的异常冒泡到ASP.NET运行时时触发),并向用户显示礼貌消息。
简而言之
- 如果发生任何奇怪的事情,请毫不犹豫地
throw
- 按照你的建议,不要处理无法处理的异常(如果你捕获到一个无法处理的异常,请重新抛出它)
- 记录!!!!!!!!!!!!!!!!!
- 不要在公共网站上向最终用户披露异常详细信息,永远不要!!默认情况下,ASP.NET会防止这种情况发生,但你仍然可以使用OnError来打印堆栈跟踪
- 使用
OnError
或Application_Error
作为单一中心点来处理所有意外异常
- 定期检查日志以查找代码问题,然后考虑维护/调试/修复它