下载第 7章 调试和错误处理前面已经介绍了使用 A S P所需要的基本技能,本章要讨论的另外一个问题是当 A S P出现错误时怎么办,A S P出错时是什么情况。当精心编排的 A S P页面出现问题停止了执行时,用户一般得到的仅是一些用处不大的建议,诸如:点击“刷新”按钮,或者“与站点的 We b管理员联系,告诉他们你的页面不能正常工作了”等等。
本章除了提供有用的信息源之外,还想提供一个帮助区域。我们将详细介绍在脚本和页面中错误如何出现,可能产生的错误类型,以及什么造成了这些错误。更重要的是,要讨论如何尽可能避免错误的发生,如不能避免又如何妥善处理。
因此,本章将要探讨页面调试技术,也就是如何花费不多的精力和时间就能找到错误并解决问题。
本章包括以下内容:
能够出现的错误类型。
如何防止各种错误的产生。
如果不能防止错误发生,如何妥善处理这些错误。
如何发现和处理脚本错误及其他类型的错误。
如何使用定制的错误页面得到错误信息。
如何记录发生的错误以监视我们的网站。
创建一个定制错误网页和一个错误日志文件。
提供相关的在线帮助。
本章不涉及如何处理使用 ActiveX Data Objects(ADO)访问数据源时出现的各种特殊类型的错误。像许多组件一样,A D O提供了自己的错误处理系统,第 8章将深入讨论这一点。本章将从讨论能出现的各种错误类型开始,使我们能够认识这些错误并采取相应的措施。
据说,在非洲最黑暗的雨林深处,有这样一群程序员,他们的程序代码从来没有出现过错误。但是,很遗憾他们从没有享受过调试一段不能正常工作的应用程序的乐趣。调试程序代码是一个真正充满快乐的工作,所以我们要面对这个问题,在调试程序的过程中检验我们的观察力和横向思维能力。大多数“真实世界”的程序员能够体验这些乐趣是一件好事。
当然,有些人会说,调试程序与其说是判断,不如说是碰运气。花费了许多时间去调试一段有错误的程序,在某种程度上可以说确实是依赖运气。但是,如果第一步从合适的地方开始查看,可能会更快地解决问题。
但这不是程序调试应采取的办法。从理论上讲,当某段程序运行失败时,应该以逻辑或顺序方式跟踪错误。作为一个聪明和有经验的程序员,这才是调试时常用的方法,只有业余人员才随意改变程序中变量的值,到处添加 R e s p o n s e,Wr i t e语句进行调试。
然而,为了能够在逻辑上跟踪程序中的错误,必须了解有关错误如何出现方面的基础知识,更重要的是知道错误出现在哪里,以便很快就能找到相应的地方。本章讨论的内容是有关程序中能够出现的不同种类的错误,错误的不同表现,以及如何记录和排除这些错误。同样重要的是,还将介绍如何避免这些错误的发生。
本章将从介绍可能出现的不同种类的错误开始,如果认为你的代码不会出现任何错误,
可以直接跳到下一章。
7.1 错误的种类
7.1.1 语法或“编译”错误当我们第一次运行新编写的程序代码时,通常看到的第一种错误类型是,syntax error” 。
这就是所说的,程序代码上的语法错误。这就像在写作中使用了错误的语法,使读者不能了解其中的含义。而解释器 (诸如脚本引擎 )和编译器对语法要求得更加严格和准确。
语法错误通常也是最早出现和需要排除的。大多数情况下,解释器和编译器会指出行号和所在行中的字符位置,以及在相应的位置上缺少的内容。下面举一个简单的例子,如下所示的这样一段程序:
我们希望得到下面的结果:
实际上得到的结果如图 7 - 1所示。
图 7-1 程序执行结果 1
文件中第 3行是 R e s p o n s e,Write 语句的第 2行。报告错误信息时,V B S c r i p t解释器忽略一行中的引导空格和制表符。所以在数完 2 6个字符之后,可以找到语法错误的地方,这里明显缺少了一个双引号。加上双引号后再运行这个页面,我们可以得到如图 7 - 2所示的画面。
第 7章 调试和错误处理 计计 2 1 1下载图 7-2 程序执行结果 2
这次又是另外一个简单错误。实际上错误出现在第 3行而不是第 4行。我们漏掉了第三行末尾的续行符 ' _ '。程序代码应该是:
1,错误出现在什么地方需要注意的是脚本解释器仅指出所发现错误的地方,但实际上那儿并不一定是错误真正出现的地方。在上例中,前面三行的语法正确的,并产生相应的输出结果,而恰恰是第 4行引起问题,因为这一行是以一种非法字符开头的,脚本解释器没有意识到这一行是上一行的一部分。
这样的错误是普遍存在的,因为通常我们主要考虑的是要输出的文本内容,而不是双引号、连字符 (在 V B S c r i p t中为 " & " )、续行符等的正确顺序。
对于关键字、内部函数名拼写错误或函数的非法参数列表而引起的语法错误,通常比较容易发现,因为错误信息提示可能就指出了错误的实际位置。例如:下面这段代码是想把明天的日期写入页面。
实际得到结果的如图 7 - 3所示。
图 7-3 程序执行结果 3
这是因为 D a t a A d d函数的语法应该是:
212计计 ASP 3 高级编程 下载所以应该改写为如下的代码:
脚本解释器检测到了我们为第二个参数提供的是一个字符型数据,而 D a t a A d d函数需要的是整型数据类型。
代码结构和脚本结构语法错误的另一个原因是:当制作网页时使用嵌套的或复杂的脚本结构,如 If Then...Else
...End If 或者 Do While...Loop。这有时会造成难以找到的语法错误。
例如下面这段程序,
产生的错误如图 7 - 4所示。
图 7-4 程序执行结果 4
为什么提示在网页程序中需要一个 E n d语句呢?看一下程序就可以发现,丢失了一个 E n d
I f,而不是 E n d,在程序的最末尾应该还有另一个 End If。
在这种情况下,根据代码的缩排格式可以很容易地找到相应的错误。特别当错误信息指出错误的大致位置时,很快就可以找到错误位置。然而,这段代码很短,如果在分界符
< %,,,% >中另外还有 4 0行代码,那么错误行号仍然可能指向最后一行 (line 56);并且如果在新第 7章 调试和错误处理 计计 2 1 3下载的代码中的其他脚本结构搞乱了嵌套的结构,错误可能会指向另一个位置。
2,关于 J S c r i p t
如果你不是一位 J a v a S c r i p t高手,并且确实想试验一些语法错误,那么就从 V B S c r i p t切换到 J S c r i p t。 J S c r i p t比 V B S c r i p t对程序编写的要求更严格,并且对关键字和变量名大小写敏感,
看下面的程序段。
运行这段程序会产生 "Object doesn't support this property or method"(对象不支持这种属性或方法 )错误,如图 7 - 5所示。
图 7-5 程序执行结果 5
原因很简单,返回目前月份数的 JScript 函数是 g e t M o n t h,而不是 G e t M o n t h。下面这段程序就可以正常运行。
当然,如果重试这段程序,可能得不到同样的错误消息。我们第一次运行这段程序时,
得到如图 7 - 6所示的错误。
图 7-6 程序执行结果 6
第 2行有什么错误?如果使用 J S c r i p t解释器,没有错误出现。错误消息说明,这是一个
V B S c r i p t语法错误。用 V B S c r i p t解释器分析 J S c r i p t程序,所以会得到奇怪的错误消息。
记住正在使用的语言之所以出现上述错误是因为在页面的代码前面记了加 @ L A N G U A G E指令。缺省是
V B S c r i p t (如果在注册表或在 Internet Services Manager中没有改变它 ),所以 V B S c r i p t引擎用于处理前面不带 @ L A N G U A G E指令的程序。即使一直使用专为自已的服务器设置的缺省语言,
214计计 ASP 3 高级编程 下载始终使用 @ L A N G U A G E指令是避免产生上述错误的好方法。这样,如果把网页移到另一个缺省语言不同的服务器上,也会得到预期的结果。
这里讲述的内容不可能覆盖所有可能遇到的语法错误,人们往往想知道为什么会出现错误,而错误信息提示并不总是像人们希望的那样准确。理想的方式应该是 A S P给我们提供一个简洁的错误显示页面,有对错误的全面精确的描述,甚至询问我们是否想自动处理错误。
事实上应用程序 Microsoft Script Debugger正试图为我们提供类似的功能,本章后面要对其进行讨论,也要概括避免出现语法错误的一些要点。现在,我们继续研究经常在网页中出现的第二类错误。
7.1.2 语义或“运行期”错误语法错误的发现和处理是令人烦恼的,但在编程中会遇到一些真正“令人兴奋”的另一类型的错误 —,语义错误 (semantic error)或称“运行期”错误 (runtime error)。这类错误仅当运行一个脚本代码或其他程序时才会发现。换句话说,完整有效的代码已经通过解释器或编译器的解释或编译,在执行时产生了错误。术语“运行期错误”通常是指语义错误的结果,
也就是说这类错误存在于代码中的语义中,当代码运行时它们才变成可见的。
这种区别来自于这种事实:程序编译器或解释器在处理程序代码之前必须建立一种内部代码的描述,涉及多种结构开头和结尾的匹配,以便标明每种结构包含什么内容,然后分析每个句子,以便知道如何执行这个句子。例如,如果在程序代码中有一个 IF Then...
Else...End If结构,解释器或编译器做的第一步工作就是分析哪些语句在,T h e n”的部分,哪些在,E l s e”部分。这一步的目的是,在对结构中的 I F条件进行测试之后,可以决定该到哪个分支去执行。
编译器 (诸如在编程语言像 Visual Basic和 C + +中见到的那种 )和解释器 (诸如用于像
V B S c r i p t和 J S c r i p t那样的脚本语言的解释器 )之间真正区别在于:编译器不试图运行程序代码,而是在对源程序进行两次预处理后,形成二进制指令或符号代码,并形成一个,e x e文件或,d l l文件。解释器不创建含有代码的文件,而是在运行时逐行执行。
1,使运行停止的错误如果程序中含有一个语义错误,通常在运行时可得到提示。如果幸运的话,当错误发生时,程序会停止,这样可以容易地找出错误所在。例如,下面这段程序定义了一个有六个元素的数组。
如果试图读或设置下标为 6的元素值,可以得到一个运行期错误,如图 7 - 7所示。
图 7-7 程序执行结果 6
第 7章 调试和错误处理 计计 2 1 5下载注意这里的错误类型是,r u n t i m e” (相当于语义 )错误,而不是语法错误。错误信息显示了错误所在行数和错误的描述,有助于我们比较容易地找到相应的错误。但这是一个简单的例子,在更复杂的程序代码中,这种错误可能出现在一些遍历一些值并把它们加到一个数组中的程序中。如下所示。
这种情况下,很可能是得到了过多的列表条目,或者是数组的索引不够,根据代码的要求,可以判断是那种错误,并且能够通过增加数组大小来解决这个错误。
或者相应地设置循环的参数来解决处理这个错误。
许多其他运行期错误能够使网页运行停止,诸如一些组件或对象的实例化失败,原因是有 P r o g I D错误,或者是因为组件没有正确安装。在这些情况下,结果总是给出 " A c t i v e X
Cannot Create Object"错误提示信息,后面跟着调用 S e r v e r,C r e a t e O b j e c t方法的行号。
2,产生错误结果的错误上面提到,如果遇到一个使程序代码停止的运行期错误,我们可能是幸运的。但是另一种情况是程序能很好地执行,好像什么也没有发生,最后产生一个错误的结果。这是最难发现和解决的错误,因为意识不到哪里出错了。例如,假设有一个网页,这个网页把用户的生日作为日期型的值,并且单独显示日期元素 (可以把它们作为三个条目加到一个数据库中 )。
216计计 ASP 3 高级编程 下载图 7 - 8是结果,是用美国日期风格月 /日 /年显示的,好像一切都没有问题。
然而如果输入一个非法日期,或者让输入文本框空着,便得到一个运行期错误,如图 7 - 9
所示。
(1) 如果不是一位 J S c r i p t专家在寻找错误时,这不是一个大问题,因为我们能够迅速发现为什么会出现错误。事实上网页停止运行有助于我们跟踪错误。然而意外的错误可能会发生。例如,用 J S c r i p t重写程序代码,由于不是一位 J S c r i p t专家,里面出现一些细小错误。
图 7 - 1 0即是运行结果,尽管程序没有停止运行并给出运行期错误,还是马上看出其中有些问题,月份不可能是 0。
图 7-10 显示生日的屏幕问题出现的原因在于 J S c r i p t的 g e t M o n t h函数返回的结果为 0 ~ 11范围内的数,因此需要再加 1,才能得到正确的结果。
第 7章 调试和错误处理 计计 2 1 7下载图 7-8 显示生日的屏幕 图 7-9 错误提示屏幕
(2) 衍生错误即使不把初始值赋给网页去和结果比较,上面这种错误也可能是相当明显的。然而,如果面对的是一个数据库系统,并且没有看到显示出不正确的结果,可能不知道为什么程序不能正确地更新数据库。更糟糕的是,如果简单地把数值做为整型数据存入数据库,可能直到有人试图对这个数据查询时才能发现这个错误。
现在,发现大约有十二分之一的成员出生在 0月份可能会使人吃惊,并会引起一些问题。
记住,不仅仅是那些 1月份出生的人员存在数据库中的信息不正确,而且每个成员都是这样。
如果有许多应用程序都能增加和修改这个数据库中的记录,跟踪这个错误可能是艰苦的工作,
特别是,不能去查找错误出现在那个程序行,而是首先要找出错误出现在哪个应用程序中。
(3) 掌握日期的用法在上面的程序中出现的日期型数据的错误不是非常明显,不论使用者输入什么样的日期,
程序代码只能给出 0 ~ 6之中的值,原因在于编码中的设定,特别是从 V B S c r i p t转换到 J S c r i p t时。
在 J S c r i p t中,g e t D a y函数返回的是周中的某一天,而不是月中的某一天,这等价于 V B S c r i p t中的 We e k d a y函数,g e t D a y函数的返回值是 0 (代表星期日 )到 6 (代表星期六 )。
注意 V B S c r i p t的 We e k d a y函数返回 1 (代表星期日 )到 7 (代表星期六 )。
因此,在 J s c r i p t中由 g e t D a t e函数获得某月的日期的正确代码是:
运行这段程序便可得到想要的结果,如图 7 - 11所示。
图 7 - 11 显示正确生日的屏幕
7.2 各种运行期错误本章前面部分展示了一些问题,包括错误如何出现、如何寻找错误和如何处理错误等等。
现在更重要的是要掌握能够发生的不同种类的错误,并且如何区分这些错误。需要记住的是,
如果知道了到哪里去找和寻找什么,调试则是比较容易的。在本章最后,将介绍错误确实出现时如何捕获错误,并且要尽可能早地阻止错误的发生。
在学习这些内容之前,首先要深入了解一下在某个阶段肯定会遇到的不同类型的运行期和语义错误,主要讨论以下内容:
逻辑错误。
218计计 ASP 3 高级编程 下载
脚本运行期错误。
ASP和 S S I运行期错误。
客户端脚本错误。
7.2.1 逻辑错误逻辑错误在脚本中通常难于跟踪,因为这些错误常常是产生错误的结果而不中止网页运行。通常只有一些值出现超出边界的情况,如在前面数组实例中看到的那样,错误才显现出来。
然而,在错误和调试环境中,一种算法并不像数学课上所学的那样复杂。从计算的角度看,算法只是指一段能完成某个任务 (通常返回某个结果 )的程序。
1,数值超界 (数据溢出 )
典型的逻辑错误一般涉及到数值,或者是涉及数据溢出等。例如,如果有名为 i m a g e 1,g i f、
i m a g e 2,g i f等的一系列图像,编写以下一段程序随机挑选一幅图象用以显示:
在网页中创建< I M G>元素用以指定随机选中的图象,例如:
然而,如果碰巧这段程序产生的结果是 i m a g e 6,g i f文件。在这种情况下,如果本来仅希望得到在 1 ~ 5中的一个结果,网页会是一个破碎的图像符号。原因是 V B S c r i p t中的 C I n t函数将值取整到最近的整数值。为了舍去小数部分,需要使用 I n t或者 F i x函数代替 C I n t。
2,运算符号的优先级其他类型的逻辑错误有按指令计算而出现的错误,例如想用除法时采用了乘法会产生错误的结果。而由于程序中数学运算符号的运行顺序或优先级,会引起一些更难发现的错误,
例如,下面这段程序可能会产生不正确的结果。
因为乘法比加法有较高的运算优先级,所以先进行计算。但是如果想把第一个数和后两个数的和相乘,必须用括号来改变这种缺省的运算优先权。
在 VBScript 5.0文档中的 VBScript Basics|VBScript Operators中,给出了所有脚本运算符号的优先级表。对于 J S c r i p t,在 JScript Tutorial|JScript Basics|JScript Operators下也可找到相应的优先级表。然而需要记住的最基本原则是:乘、除法优先于加、减法。
3,管理和格式化字符串数据从计算意义上考虑,具有计算功能的任何结构或函数都可看作一种算法。例如,可以从数据库中取值构成一个字符串,代表顾客的名字。这里不涉及如何从数据库中提取数据 (本书的后面部分进行讨论 )。下面程序的功能是字符串连接。
第 7章 调试和错误处理 计计 2 1 9下载运行这段程序可以得到如下结果:
但不是每个人都和 " J a n e t "一样,有一个中间名字。并且许多人可能没有头衔,所以可能仅仅得到:
这当然不是一个能引起脚本不能运行或者产生运行期错误的致命错误。然而,对于用户来说,提供这样的脚本是不可接受的。最好程序能在输出字符串之前检查名字的每一部分。
上面这段程序保证了空格和小数点仅加在名字中有值的地方。如果仅给 s t r O t h e r字符串赋值,而对其他都不赋值的话,将在开始处得到一个空格。然而出现这种情况的可能性非常小。
如果有姓的话,通过仅添加,o t h e r”部分可以防止这种错误的发生。
最坏的情况是结果为一个空字符串,可以检查这种可能性并中止打印。
7.2.2 脚本运行期错误使用一个不存在的函数,或者破坏了脚本语言使用的规则,会出现脚本运行期错误。许多错误是语法错误 (本章前面讨论过的 ),但是许多错误是由于所赋的值和函数参数的要求不一致引起的。
例如,用一个窗体收集来自用户的日期,并存入数据库中,或者用其他方式进行处理。
为了确定日期是有效的,在把数据插入数据库之前使用 C D a t e函数:
220计计 ASP 3 高级编程 下载如果用户在填表时出现了差错,程序便会产生一个脚本错误,如图 7 - 1 2所示。
图 7-12 出错信息的屏幕查看错误信息,可以发现错误是由执行程序代码的脚本引擎产生的。错误号用十六进制显示出来,它是由 V B S c r i p t错误号和十六进制数 0 X 8 0 0 A 0 0 0 0相加得到的 (见第 4章 ),上例中
V B S c r i p t错误号是十六进制 0 x D,或者十进制数的 1 3。
大多数微软技术 (包括 A S P )返回的错误号是由 8位十六进制数组成的。第一位字符总是 8,表明这个状态信息是服务器错误信息。后面跟着 2位 0,然后是服务代码。
对 V B S c r i p t和 J S c r i p t错误,服务代码总是 " A ",最后 4位字符是用十六进制数表示的错误号。
如果查看一下 V B S c r i p t文档,你会发现 1 3号错误是,Type Mismatch”错误。当然,我们从 A S P错误页中显示的错误描述中已经知道了这一点。然而,在本章后面我们将要看到,在错误处理技术中,得到错误号是非常有用的。
注意,在错误信息显示窗口中,显示的是服务器对错误的反馈信息。 H T T P状态代码为
5 0 0,1 0 0,属于,Internal Server Error” 。在第 4章,讨论 A S P定制错误网页的工作方式时,我们发现这种错误常常因为载入了错误网页。本章后面,将会看到在网页中如何处理这些错误。
7.2.3 ASP和 S S I的运行期错误脚本错误是由正在使用的脚本引擎发现的,然而 ASP DLL和 SSI DLL也能发现脚本错误,
尽管它们与使用的脚本引擎无关。典型的 S S I例子是在 # i n c l u d e指令中给文件一个错误的名字或路径。错误由 SSI DLL或 A S P发现的,而不由脚本引擎发现。可看到此时错误类型是
,Active Server Pages”,A S P内部错误代码是,ASP 0126”,如图 7 - 1 3所示,然而在这种情况下,错误号是 4 0 0 5,指出了这是一种为 SSI DLL(ssinc.dll)定义的特殊错误错误。
图 7-13 出错信息的屏幕第 7章 调试和错误处理 计计 2 2 1下载
A S P错误代码总览对于在 ASP DLL中造成失败的错误,表 7 - 1是返回的错误代码。当这类错误发生时,你可以在 A S P E r r o r对象的 A S P C o d e属性中找到这些错误代码。
表 7-1 ASP错误代码错误代码 错误消息和扩展信息
A S P 0 1 0 0 Out of memory(内存溢出 )
A S P 0 1 0 1 Unexpected error(函数返回 e x c e p t i o n _ n a m e )
A S P 0 1 0 2 Expecting string input(期待字符串输入 )
A S P 0 1 0 3 Expecting numeric input(期待数字量输入 )
A S P 0 1 0 4 Operating not allowed(操作不允许 )
A S P 0 1 0 5 Index out of range(数组下标溢出 )
A S P 0 1 0 6 Type Mismatch(数据类型不匹配 )
A S P 0 1 0 7 Stack Overflow(处理的数据量超过了允许的范围 )
A S P 0 11 5 Unexpected error(出现在外部对象中的可捕获的错误 e x c e p t i o n _ n a m e,脚本不能继续运行 )
A S P 0 1 7 7 S e r v e r.CreateObject Failed(无效的 P r o g I D )
A S P 0 1 9 0 Unexpected error(当释放外部对象时,出现的可捕获的错误 )
A S P 0 1 9 1 Unexpected error(在外部对象的 O n S t a r t P a g e方法中出现的可捕获的错误 )
A S P 0 1 9 2 Unexpected error(在外部对象的 OnEndPage 方法中出现的可捕获的错误 )
A S P 0 1 9 3 OnStartPage Failed(在外部对象的 O n S t a r t P a g e方法中出现错误 )
A S P 0 1 9 4 OnEndPage Failed(在外部对象的 OnEndPage 方法中出现错误 )
A S P 0 2 4 0 Script Engine Exception(脚本引擎从 o b j e c t _ n a m e抛出异常 e x c e p t i o n _ n a m e )
A S P 0 2 4 1 CreateObject Exception(object_name的 C r e a t e O b j e c t方法所导致的异常 e x c e p t i o n _ n a m e )
A S P 0 2 4 2 Query OnStartPage Interface Exception(查询对象 o b j e c t _ n a m e的 O n S t a r t P a g e或 O n E n d P a g e
方法所导致的异常 e x c e p t i o n _ n a m e )
A S P错 误通 常仅当 组件 有问题 或服 务器本 身有 问题时 才出 现。最 常见 是使用
S e v e r,C r e a t e O b j e c t时的 ASP 0177错误和严重的 ASP 011 5错误。 ASP 011 5错误通常表示组件程序代码中发生的错误,而 ASP 0177错误通常是由不能正确安装组件引起的或者由我们指定的
Prog ID字符串的错误引起的。
7.2.4 客户端脚本错误到目前为止,我们已了解了来自 A S P的错误。然而 A S P也经常用于创建包含客户端脚本的网页。如果包含客户端代码的< S C R I P T>元素没有被设置成 R U N AT = "SERV E R "属性,A S P
将不考虑服务器,而把网页信息不加改变地传送到客户端。
因此,如果打开了一个 A S P网页,并且显示的是一个浏览器错误对话框,就不应该在服务器端寻找 A S P程序代码的错误。浏览器看不到 A S P程序代码,所以不能识别任何错误,如果有一个对话框出现在客户端,那么在客户端代码中必定有一个错误。
1,语法错误如果在网页中的客户端程序代码有语法错误的话,当脚本下载到客户端,浏览器便会出现相应的错误。尽管网页中内容仍可正常载入 (除非由这些客户端脚本代码动态装入 ),但网页停止执行。用户将看到一个包含错误细节的对话框,或者是一个指示网页包含错误的状态条消息。
现代浏览器趋向于隐藏网页脚本错误的细节,而仅在状态条上显示一个小的错误图标。
222计计 ASP 3 高级编程 下载在 IE 4.0和 IE 5.0中,正常的错误对话框可以通过 Internet Options对话框的 A d v a n c e d页进行设置来激活,如图 7 - 1 4所示。
处理脚本程序代码中的客户端错误和在服务器端相似,并且通常会更容易些,
因为经常可以直接从服务器目录中通过双击来下载网页。一般不需要通过 We b服务器和 H T T P获得网页来观察浏览器中的结果,
其中的唯一不同是一些服务器交互由客户端脚本来完成,如使用 R D S的数据绑定或者动态装入。
2,运行期或语义错误在客户端脚本中,通常可能会遇到语法错误,也会经常遇到运行期或语义错误。
事实上,在客户端,这种现象是很普遍的。
因为在客户端不能像服务器端那样对脚本的环境进行控制,不能肯定用户在他们的机器上正运行什么,实际上在服务器上仅能从一些组件如 Browser Capabilities中得到大概情况。
所以,使用客户端对象或特殊版本的脚本语言和属性的脚本程序很可能不能正常工作。
尽管如此,处理客户端错误和处理服务器端错误是差不多的。
3,在服务器上创建的客户端程序代码在错误发生时,作为“客户端对话框对应于 A S P错误页面”规则 (关于出错的地方 )的一个特别的例外是,使用 A S P程序代码在服务器上动态地创建客户端程序代码。例如,可能想在
A S P中进行求值运算,然后把数据传给运行在客户端的脚本代码,可能最容易的方法是把数据作为一个变量插入脚本代码中:
在客户端,在 A S P处理这个页面之后,将得到的是:
第 7章 调试和错误处理 计计 2 2 3下载图 7-14 Advanced页面设置屏幕可以忽略 R U N AT= " C L I E N T "属性,但是加上这一项可以使得在查看运行代码的
A S P网页时更加清楚。
这样,如果在某个位置想把服务器端数据库中的数据加入到一个客户端数组中,可以采用下面的程序实现:
这段服务器端 A S P程序代码产生的客户端代码,在客户端运行时创建书名标题数组。同时产生的客户端脚本错误出现在浏览器的错误对话框中。错误的原因是以 a r r B o o k s命名的数组是由 J a v a S c r i p t代码运行在客户端时创建的,仅能接受 9个书名;而服务器端代码能很可能产生多于 9个的书名,具体多少由源数据库中的记录数来决定。这相当于如上客户端代码:
这个页面只有经过修正之后才能正常工作,可以通过增加数组大小,也可以通过控制来自数据库的记录数使其正常工作。
7.3 防止错误上面已经看到了能够出现的一些不同类型的错误,并且有了一些查找错误的感觉。下面
224计计 ASP 3 高级编程 下载将考虑如何避免把错误引入程序中,尽管不能保证所编的程序没有错误,但是这里概括的许多技术有助于减少错误数目。
良好的编程习惯在编程中避免出现错误是和良好的编程习惯相关的,这里有许多工作我们要做,以减少把错误带进网页的可能性。可能有些人因采用某个技术而走向极端,甚至一定程度上在某个特殊问题上因书生气十足而引入了更多的错误。当然编程人员也不可能采用了这里列出的所有技术。
要考虑的主要内容是:
代码的格式化和缩进编排。
变量显式表明。
变量转换为合适的数据类型。
使用有意义的变量命名约定。
封装脚本。
注意潜在的错误情况。
程序测试。
1,代码的格式化和缩进编排许多 V B S c r i p t编程员懒于格式化编排其书写的程序。尽管这并不阻碍程序运行,但这使得查找何处产生了错误变得困难。例如,在前面我们看到的程序中,丢失了一个 End If,由于嵌套结构的缩进,错误在哪里是相当明显的:
如果程序看起来像下面所示的那样,寻找错误将不是一件易事:
2,显式表明变量
V B S c r i p t支持 Option Explicit语句。在一个脚本页面的开头插入 Option Explicit语句时,可第 7章 调试和错误处理 计计 2 2 5下载以避免使用没有用 D i m命令 (或用于动态数组的 R e D i m )定义的变量。似乎不需要这么做,因为脚本语言允许通过给一个变量赋值来创建一个需要的变量。然而用 Option Explicit 进行定义有助于避免错误,特别是那些难以发现的引起脚本产生不正确结果的逻辑错误。
例如,编写如下程序:
运行这段程序不会产生错误 (当然,除非用户给销售合计值赋了非法的值 )。然而这段程序总是会产生 0的结果,因为在程序的最后一行中 S n g C o m m i s s i o n P e r c e n t变量名拼写错了。脚本解释器将产生一个新的变量名 (叫作 S n g C o m i s s i o n P e r c e n t ),由于没有赋值,在数学计算时返回值总为 0。
为了防止这种错误,仅需在程序开头增加 Option Explicit语句。
这时,当脚本引擎试图解释程序时将识别出一个语法错误,并且能够指出此变量没有声明,如图 7 - 1 5所示。
图 7-15 显示的错误信息在 J S c r i p t中引用一个没有声明的变量将返回一个 " U n d e f i n e d "信息,并且在试图使用变量之前,能够检测到这种情况。
3,变量转换为合适的数据类型回头看看前面的程序,可能发现用 C C u r函数把用户提供的数据转换成了货币型数据类型。
在 V B S c r i p t中,有一系列类似这样的数据类型变换函数,在第 3章中有详细的描述。
226计计 ASP 3 高级编程 下载如果不能完成变换,也就是说变量内容对新数据类型来说是无效的,便会出现一个运行期错误。然而,如果对数值类型进行变换,我们希望这个数值是有效的,并且能在程序中使用。因此能够检测一个无效的值对于防止错误的出现是一件“幸事” 。
如果想把输入空格作 0对待,并且把任何其他无效的输入作为用户错误对待,前面程序变为:
在 J S c r i p t中,所有的变量都是对象,并且有 t y p e O f ( )方法。可以使用 t y p e O f ( )来确定存在变量中的数据是什么类型,见第 3章中的详细论述。
也可以对 " n u l l " ( V B S c r i p t中为 N u l l )进行测试保证在程序使用各种变量之前它们已经赋了值。一个特例是从数据库中获得数据时,数据库中的字段内容经常是 N u l l,表示没有数据。
4,变量命名和编码约定阅读过本章和前面几章后,读者可以看出我们对变量名使用三个字母的前缀,用以指明它所代表的数据类型。尽管在这两种脚本语言中用 A S P提供的所有变量都是 Va r i a n t (或 J S c r i p t
中的等价物 )类型的,但用变量名来区分出存储在其中的数据的类型仍是非常有用的,有助于防止编写程序时出错。
有许多不同的变量命名约定,经常使用的见表 7 - 2。
表 7-2 变量类型及前缀变量类型 前 缀布尔型 ( B o o l e a n ) b l n
字节型 ( B y t e ) b y t
日期 /时间型 ( D a t e / Ti m e ) d a t或 d t m
集合型 ( C o l l e c t i o n ) c o l
双精度型 ( D o u b l e ) d b l
整型 ( I n t e g e r ) i n t
长整型 ( L o n g ) l n g
对象型 ( O b j e c t ) o b j
单精度型 ( S i n g l e ) s n g
字符型 ( s t r i n g ) s t r
第 7章 调试和错误处理 计计 2 2 7下载对一个包含函数和子程序的网页,指出某个变量是否已经声明或存在于任何函数和子程序之外是非常有用的。若已经声明,则该变量对网页来说是全局变量。对全局变量加上,g”
前缀,所以一全局字符串变量可被命名为 g s t r M y s t r i n g;类似地,以,a”为前缀的变量是数组或数组元素。
程序注释许多编程人员感觉到对程序增加注释不仅增加了不必要的开发时间,而且也减缓了网页的运行速度,因为脚本解释器每次必须先读整个程序,然后再跳过这些注释。尽管这种观点有一定的道理,但是一个月后再回过头来想读懂没有注释的程序,是非常困难的。
至少应该对常用函数和子程序进行注释以便你和其他人能重新使用这些程序。特别是,
使用新的 S e r v e r,E x e c u t e方法更加容易 (详细情况参阅第 4章 )。下面是微软提供的一个例程的注释格式。
5,封装脚本语言以便代码重用刚刚看到了如何注释子程序和函数以便易于重新使用。面向对象编程的原理是建立在程序代码重用的基础上的,并且 S S I的 # i n c l u d e和新的 S e r v e r,E x e c u t e方法使调用存储在程序库中的函数更容易。
例如,如果有一系列函数用于计算税收和商品的的应付费用。可把包含这段程序的页面插入其他页面中:
包含文件必须含有脚本定界符,或者用 <SCRIPT RUNAT = "SERV E R " >,,< / S C R I P T >或者用 <%.,,.%>,每一个子程序和函数应该采用其要求的数值做参数,并且用函数值或更新的参数返回结果。不能使用全局变量,况且不同网页之间的全局变量也是不可用的。但在主网页中的程序能安全地调用所需的函数和子程序。
另外可使用 S e r v e r,E x e c u t e (或者 S e r v e r,Tr a n s f e r )把执行转到另一个网页。如果有一段 A S P
代码用来为客户创建在线采购一览表,这种方法是非常有用的。它包含 H T M L用来创建标题、
表格,用代码进行计算并用 R e q u e s t集合的内容填写相应值 (记住不能使用 S e r v e r,E x e c u t e或
S e r v e r,Tr a n s f e r把脚本变量传到另一个网页 )。另外,运行的网页能够支持函数、类定义 (在
V B S c r i p t中 ),或者其他设计为可重新使用的内容。
6,注意潜在的错误情况编程时不管如何仔细,比如在使用和对变量类型转换之前对变量值进行测试,但总还是有一些情况不能避免错误的出现。明显的例子是:当使用 F i l e S y s t e m O b j e c t对象的方法设法访问一个用户指定的文件时,不能确定这个文件是否已移动、删除或者标记成只读型,所有这些操作都可能使程序不能工作。
其他类似的情况可能是,当访问数据库或其他数据存储时,对用户帐户而言,有时要求
228计计 ASP 3 高级编程 下载某一层权限。在这种情况下,可能因为需要的访问不能实现,使程序不能工作。
可以通过采取预防性措施编写程序,来测试类似的潜在错误。例如,可以使用 To o l s组件或者 F i l e S y s t e m O b j e c t对象的 F i l e E x i s t s方法来查看,是否一个文件在访问之前就已存在了;或者使用 Permission Checker组件来查看当前用户帐号是否有访问需要的文件或资源的权限;也可以通过使用 F i l e S y s t e m O b j e c t获得一个文件的属性设置,以便在删除或重写之前查看文件是否是只读的。
如果不考虑可能发生的错误并防止错误发生的话,这些情况和许多类似的情况都可能是潜在的运行期错误源。
7,最后的测试很明显,测试是对错误的最好防范方法。错误能通过应用程序影响到其他操作,如果不及时发现能引起不可估量的损失。用各种数值 (如用户提交的,或者访问一个数据库得到的数据 )对网页进行测试。同时,更重要的是,如果采用我们不希望的值会发生什么。程序能避免这些情况产生其他错误或者避免扰乱正在测试的子程序吗?
好的测试技术应该包括一系列值,如期望的值、边界条件值和超出边界的值。用期望传送到网页的值进行测试是应该经常做的工作,同样超出边界的值通常比较容易阻止。例如,
可以限制可接受的数值范围为- 1 0 0 ~+ 1 0 0,程序如下:
然而要记住查看边界条件,上面的程序能处理 - 1 0 0和+ 1 0 0吗?想把数据限制在 - 1 0 0 ~+
1 0 0中吗?取 0时会发生什么?上面的程序会显示,Divide By Zero”错误而最终停止执行吗?
7.4 处理错误即使采用了防御性编程技术之后,错误仍能进入到网页,这可能是因为测试并不充分,
或者是因为所依靠的一些其他资源或服务没有正确工作。为了防止页面出现问题,在程序中要能够进行定制错误处理。
7.4.1 ASP缺省错误处理器前面已经看到过,A S P和 I I S能找出网页中的大多数错误,并且能自动生成错误信息页,
这些错误几乎总是 5 0 0,1 0 0类型的,并且 I I S用 S e r v e r,Tr a n s f e r方法装载以 5 0 0 - 1 0 0,a s p命名的缺省错误页,然后传送给客户。第 4章介绍了这一工作过程,以及如何与定制错误网页接口。
然而,运行期脚本错误不总是由 I I S发现的,当一个运行期错误发生时,脚本引擎会查看一下目前执行点或语句的环境。如果正在执行一个子程序或函数,缺省的脚本引擎错误处理器通过终止子程序的运行并返回调用子程序的地方来指出错误。
在这里,程序会查看是否实现了其他的错误处理器,如果没有的话,又会重复这个过程,
然后返回到调用子程序的地方。当子程序返回到网页的主程序 (在任何其他子程序或函数外面 )
时,程序又会查看是否实现了任何其他的错误处理器。在这个过程中,只有确实没有发现其第 7章 调试和错误处理 计计 2 2 9下载他的错误处理器,程序才给 A S P提示错误,指示 I I S把执行转到缺省的错误页面。
7.4.2 VBScript错误处理在 V B S c r i p t中,可以使脚本解释器不处理其找到的任何错误,并且使用 On Error Resume
N e x t语句继续运行下个语句。一旦这个语句已被处理,脚本引擎将继续运行后面的程序,而不理会已经发现的任何错误。然而,这种过程仅适用于顺序执行语句的环境,换句话说,不适用于嵌套的函数或子程序。
1,使用 on Error Resume Next 语句一个错误在子程序中出现时,如果没有运行 On Error Resume Next语句,那么错误将被交给调用它的环境,这个过程一直重复到找到运行 On Error Resume Next语句的环境继续运行,
或者找到缺省的脚本错误处理器,把错误交给 A S P并且 I I S显示缺省错误网页。这个过程如图
7 - 1 6所示。
图 7-16 错误处理过程这种错误调用链意味着可以创建防止使程序停止运行的运行期错误的函数和子程序。如果在子程序的开头放置一个 On Error Resume Next语句,任何运行期错误会中止这个子程序的运行,但是调用该子程序的程序将继续运行而不会引起网页的停止。
例如,如果需要向一个文件中写入字符串,可以通过一个独立的函数对文件进行访问文件,防止错误中断整个程序的运行:
注意上面的程序在试图处理每个程序语句之前,先检查 V B S c r i p t的 E r r对象的 N u m b e r属性。
如果这个值为 0 (还没有出现错误 ),那么就能够继续对文件的写入和创建过程。然而如果错误确实发生了,脚本引擎将设置 E r r对象的属性的值,并且继续处理下一行。
只要不引起错误而能正常运行,函数的返回值将设置为,Tr u e” 。否则函数将返回,F a l s e” 。
在编程中可以在对其进行测试以后,再使用该函数和采取其他行动。
下面是一个简单的例子,我们希望对任务的每一部分采用一个独立的函数,以便能更精
230计计 ASP 3 高级编程 下载确地辨别出错误产生在何处。这样,调试时也更容易阅读代码。在页面的主程序中,可以调用三个单独的函数。
2,使用 On Error Goto 0
在 ASP 2.0(尽管没有文档记录 )和 A S P 3,0中,也能使用 On Error Goto 0语句恢复缺省的错误处理行为。在运行这个语句后,发生的运行期错误将导致缺省错误处理,在环境链中检查每个嵌套的程序,直到主页面代码。如果没有其他的环境关闭缺省错误处理,网页的执行将停止并显示 I I S缺省错误网页。
3,VBScript Err对象在前面的例子中,关闭缺省错误处理时,通过检查 VBScript Err 对象的 N u m b e r属性,查看错误是否已经出现。 Err 对象存储了关于运行期错误的信息,表 7 - 3和表 7 - 4给出了 V B S c r i p t
Err 对象提供的方法和属性。
表 7-3 VBScript Err 对象的方法方 法 说 明
C l e a r 清除当前所有的 E r r对象设置
R a i s e 产生一个运行期错误表 7-4 VBScript Err 对象的属性属 性 说 明
D e s c r i p t i o n 设置或返回一个描述错误的字符串
N u m b e r (缺省 )设置或返回指定一个错误的值
S o u r c e 设置或返回产生错误的对象的名称使用这些属性可以检查发生了哪种错误。例如,可以根据错误号采取不同的措施,也可以用 S o u r c e和 D e s c r i p t i o n的属性值为用户提供错误信息,或者传送到一个文件中。
也可以使用 Err 对象生成一个错误。为什么要做这些呢?因为有时想把一个定制的错误消息传送给用户。可以把 E r r对象的属性设置成所希望的任何值。然后调用 R a i s e方法来产生这种错误,这样做会停止程序的运行,并且把错误沿调用链向回传递。
下面的例子显示了在服务器磁盘上读取一个文本文件时,如何处理错误。注意如何使用常数 v b O b j e c t E r r o r,以确定所选择的错误号不会和一个已存在的错误号混淆。通过把任意选第 7章 调试和错误处理 计计 2 3 1下载择的错误号加到此常数中,就能够保证和预定义的错误号不混淆。
调用这个函数的代码可以使用 On Error Resume Next语句,并且能捕获这个函数产生的错误。
7.4.3 JScript错误处理在 5,0版之前,J S c r i p t的错误处理能力并不出色,然而在 5,0版中情况改变了,J S c r i p t采用了一套和 J a v a以及 C++非常类似的错误处理系统。它掌握起来尽管不像 V B S c r i p t技术那样容易,但人们认为在错误处理上,J S c r i p t走在前头。
在第 1章中,在讨论这两个主要脚本语言的新特点的时候,已详细讨论了 J S c r i p t错误处理,
这里不再重复。如果阅读第 1章时跳过了这部分,可以回到那里看看。
7.4.4 使用 I I S错误页面与 A S P错误处理过程相关的内容是为 I I S提供可定制的错误页面。事实上,在 IIS 4.0中也有这个特点。但新的 A S P内置对象 A S P E r r o r,更易于使用且提供更加强大的功能。
在第 4章,当我们研究 S e r v e r,E x e c u t e和 S e r v e r,Tr a n s f e r方法时,已经讲述了如何建立定制的错误页面。我们也讨论和使用了 A S P E r r o r对象,但这种方式受到了一定的限制。在这一部分,将介绍如何将定制的错误网页和 A S P E r r o r对象结合起来建立一个更好的处理 A S P错误的方法。
我们可以使用 V B S c r i p t检查 A S P E r r o r对象的内容,从而创建一个定制的错误页面。构建
232计计 ASP 3 高级编程 下载一个包含错误内容全面信息的字符串,且写入到服务器磁盘上的日志文件中。然而网页的设计仅使访问者看到网页不可用这样一条信息是不行的,应该使访问者能够选择是重新载入上一个网页还是回到主页,使他们没有意识已经发生了错误。
尽管我们采用 V B S c r i p t创建这个网页,但其使用的一些特性对 J S c r i p t来说也是适用的,这两种脚本语言的相互转换也是比较容易的。
可以从 h t t p,/ / w w w,w r o x,c o m站点下载本章及本书其他章节的示例文件。
1,设置定制的错误页面在能使用定制的错误页面之前,必须在 Internet Services Manager进行相应的设置 (设置方式见第 4章 )。把示例文件装入计算机的 w w w r o o t目录中,打开 C h a p t e r 0 7子目录的 P r o p e r t i e s对话框,在 Custom Errors选项卡中,滚动列表并选中 H T T P错误,5 0 0,1 0 0”条目,点击 E d i t
P r o p e r t i e s按钮,并键入定制的错误页面 C u s t o m _ e r r o r,a s p的 U R L,如图 7 - 1 7所示。
图 7-17 Custom Errors选项卡现在 C h a p t e r 0 7子目录中的页面出现一个 A S P错误时,就会打开定制的错误页面。
2,使用定制的错误页面在浏览器中打开 chapter07目录并选择到,Using a
Custom Error Page”的链接,这个页面显示了一系列用于产生各种类型的错误的按钮,点击标有,Load a
Page with a Syntax error”的按钮,如图 7-18所示。
这将载入了一个名为 s y n t a x _ e r r o r,a s p的简单页面。然而看不到这个页面,因为这个页面包含了一个语法错误。 A S P终止这个页面的编译 /执行,并把执行转到定制错误页面,这个页面展示了错误的细节和两个按钮,这两个按钮用以返回上个页面 (主菜单 )或返回 We b站点的缺省主页,如图 7 - 1 9所示。
第 7章 调试和错误处理 计计 2 3 3下载图 7-18 演示定制错误页面的屏幕 1
图 7-19 演示定制错误页面的屏幕 2
这个页面也把错误报告追加到服务器磁盘 C,\ t e m p文件夹中名为 c u s t o m _ e r r o r,l o g的日志文件中,可以在文本编辑器中打开并查看它,图 7 - 2 0所示的日志文件已经记录了几个错误。
图 7-20 日志文件如果在页面中得到了一个信息,指明日志文件不能写入信息,可能是因为
I U S R _ m a c h i n e n a m e ( I U S R _计算机名 )帐号没有访问 C,\ t e m p目录的权限。当测试这个页面时,应该给予 IUSR_machine name帐号对这个目录的全部控制权,或者改变
c u s t o m _ e r r o r,a s p页面的程序代码以指向一个 I U S R有全部控制权的文件夹错误消息出现在页面中的唯一原因,是因为在 c a u s e _ e r r o r,a s p页面中我们选择了相应的复选框。如果关闭该选项并再次点击按钮,便看不到错误的详细情况,然而错误信息仍然记录在服务器磁盘上的 c u s t o m _ e r r o r,l o g错误日志文件中。
,Display debugging information”复选框给定制错误页面 (而不是日志文件 )提供了更多的信息,有助于调试那些使用 A S P内置对象集合值的页面,如图 7 - 2 1所示。
在本章下面部分,将再讨论这一个问题,同时也可以了解,Cause an Error”页面上的其他按钮所提供的其他种类的错误信息。注意有一些按钮能够比其他的按扭能够提供更多信息。
特别是只有最后一个按钮给出 A S P错误代码的值 (这里是 ASP 0177)。
( 1 ),Cause An Error”页面的功能与先前讨论的示例页面一样,引起错误的页面使用同样的技术,用< F o r m>把值提交给
234计计 ASP 3 高级编程 下载图 7-21 cause_error,a s p页面的选择框同一个页面。然后 A S P程序查看窗口上点击的是那个 S U B M I T按钮,然后运行代码的相应部分。
同时查看是否页面上两个复选框是否选中,如果是这样,程序首先设置一个或两个会话级的变量以指明这一点。
由于使用了 S e r v e r,Tr a n s f e r,当错误发生时,正在运行的网页的整个 A S P环境由 I I S传给定制错误页面。然而,脚本变量的值并没有传给定制错误页面,所以必须使用 S e s s i o n变量,或者把值添加到 R e q u e s t,F o r m或 R e q u e s t,Q u e r y S t r i n g集合以便把值传送给定制错误页面。
设置了 S e s s i o n变量之后,程序继续查看点击了哪个按钮。每个类型的错误 (除了第一类型外 ),都是由运行相应的 A S P代码产生的,第一类型的错误需要调用另一个页面。
(2) 定制错误页面的工作知道了如何创建错误后,让我们来看看定制的错误页面。在前面的章节里已经知道了构建网页需要的理论,这里再概要地描述一下其工作过程。第一步是关闭缺省的错误处理器以便页面程序不被另一个错误中断。第二步通过创建一个新的 A S P E r r o r对象收集原始错误信息。
第 7章 调试和错误处理 计计 2 3 5下载进行这个工作时要格式化一些值,并把它们转换成合适的数据类型。
现在构建一个错误报告字符串,这段程序看起来复杂,但实际上仅是一系列 If Then语句的嵌套,用以产生良好的报告格式,没有任何空的段落。如果错误是语法错误,来自
A S P E r r o r对象的 S o u r c e属性的源代码可在 s t r S o u r c e C o d e变量中得到,可以使用这个变量及
l n g C o l N u m的值 (从 A S P E r r o r对象的 C o l u m n属性中得到 )增加一个标记用来指明在源程序中的什么地方发现了错误。
236计计 ASP 3 高级编程 下载
(3) 记录错误用名为 s t r D e t a i l的字符串变量创建了错误报告后,可以像在第 5章中做的那样,采用
F i l e S y s t e m O b j e c t对象把它追加到日志文件中。如果成功,布尔型,failed flag”变量将被设置成 F a l s e。
(4) 跳转到另一个页面现在准备在网页中创建一些输出。在此之前,需要检查错误细节以确定下一步要做什么。
例如,可用 A S P E r r o r对象的 N u m b e r或其他属性检查错误类型。在这里,可认为,Ty p e
M i s m a t c h”错误不是代码中有错误,可能是由于用户在文本框中输入错误数据产生的。所以不显示这个网页的剩余部分,而是跳转到另一个网页是否决定这样做依赖于你自己的情况以及你打算发现、记录或显示的错误类型。需要注意的是,因为我们不想把目前的网页环境传送到新的网页上,所以选择使用 R e s p o n s e,R e d i r e c t
语句而不用 S e r v e r,Tr a n s f e r语句。
(5) 显示错误信息最后,显示错误报告和其他信息以及返回到上一个网页或主页的按钮。
第 7章 调试和错误处理 计计 2 3 7下载对上面这段程序需要注意的是:在定制错误页面里,不能使用 S e r v e r,E x e c u t e方法。如果我们这样做的话,至少程序不能正常工作。当程序把执行转到特定的网页时,程序不会再返回到当前网页,这就是我们使用 S e r v e r,Tr a n s f e r方法载入显示调试信息的网页的原因。这是下一部分要讨论的问题。
7.5 程序调试 — 发现及处理错误读完上面内容,读者一定很想创建一个没有错误的 A S P网页。但你可能会发现网页并不能工作,怎么办,只有进行调试。
在这一部分,首先简要看一下能使调试更容易的一些工具。 Microsoft Script Debugger试图把调试支持工具提高到像 Visual Basic,D e l p h i和 Visual C++等大多数传统编程环境的水平。
然而,下面将首先讨论一些更传统的有助于跟踪出现在网页中的错误的技术。
7.5.1 常规调试技术在第 2章中,已经看到如何使用 R e s p o n s e,Wr i t e方法以及 R e q u e s t集合来显示集合的内容。
如果代码要使用来自请求的值,首先要做的是保证所需的值存在。很容易出现的问题是错拼或改变的< F O R M>网页中 H T M L控件的名字,或者创建附加在 U R L后面的查询字符串时出现了错误的客户端。
1,显示各种集合内容当程序试图用使用用户提供的值运行时,可能没有得到所期望的结果,或者什么结果也没得到。记住,引用 R e q u e s t对象的集合中一个并不存在的值 (例如,在窗体上没有一个名为
,T h i s C o n t r o l”的控件时,使用 R e q u e s t,F o r m ( " T h i s C o n t r o l " ) )不会引起错误。结果可能只得到一个空字符串。如果期望查找存储在用户的 S e s s i o n对象或全局 A p p l i c a t i o n对象变量中的数值,
同样可能出现这种情况。
如果创建一个页面用来显示所有 R e q u e s t对象集合,S e s s i o n和 A p p l i c a t i o n对象的 C o n t e n t s
和 S t a t i c C o n t e n t s集合的内容,可从任何网页使用 S e r v e r,E x e c u t e对其进行访问。所需要做的工作是把下面程序行加到 A S P网页中,用来显示集合的全部内容。当然,根据服务器上文件存
238计计 ASP 3 高级编程 下载放的位置,必须给文件设置相应的路径。
这是一种很好的方法,保证我们希望在 R e q u e s t,S e s s i o n和 A p p l i c a t i o n集合中找到的任何值确实存在,并且包含了合适的值。在本书的示例文件 C h a p t e r c 0 7子目录中提供了一个相应的文件,取名为 d e b u g _ R e g u e s t,a s p。它基本上是用于第 2章的 s h o w _ r e q u e s t,a s p网页和用于第 3章的 s h o w _ a p p l i c a t i o n,a s p和 s h o w _ s e s s i o n,a s p网页的一个组合,但删除了部分 H T M L程序代码。
它只是简单地遍历了集合并把值放到当前页面中。
可以通过运行,Custom Error Page”实例来查看这个页面。这个实例在本章前而看到过,
打开时请选中,Display debugging information”复选框,或者直接在 c h a p t e r 0 7目录中的主菜单网页中打开。
2,显示中间值在网页中查看运行情况的第二个方法是显示网页运行时变量的值。当大概知道了错误来自何处,哪个变量在起作用时,这种传统技术还是不能废弃的。但由于 IIS 5.0网页缓冲方式的改变,使得使用这项技术比较困难。
在 A S P和 I I S的先前版本中,缺省时关闭页面缓冲,并且几乎没有人想到将缓冲打开 (使用
R e s p o n s e,B u ffer = Tr u e打开 ),除非想使用 R e s p o n s e,R e d i r e c t完成网页的再定向 (参看第 2章 )。
响应多个请求时,由于缓冲减小了网页间切换的次数,从而提高了 I I S的效率。
然而,当出现一个使运行停止的运行期错误时,I I S自动调用 R e s p o n s e,C l e a r方法,再调用
S e r v e r,E x e c u t e来装入定制错误网页,因此写进网页的任何输出都丢失了。解决方法是暂时增加下面的程序行:
<%Respvnse.Buffer = False %>
此程序行放在页面顶部 < @ L A N G U A G E..,>指令后面,任何由 R e s p o n s e,Wr i t e语句生成的调试输出将出现在定制错误网页的顶部。记住在完成网页调试之后将它去掉。
强行使程序运行通过一个错误点,然后显示可疑的变量值,这种方法有时也是有用的。
只需在网页开始处附近增加 On Error Resume Next语句,然后就能访问 E r r对象 (在 V B S c r i p t中 ),
并显示错误号、错误源和描述。
3,检查组件属性值如果使用的组件具有在 A S P脚本代码中设置的属性,在完成设置之后,并且调用组件方法之前和之后,能通过显示所有属性 (或仅是可疑的属性 )来跟踪错误。当一个方法运行时,可能发现属性值意外地被组件改变了,这或许是故意的,或者是因为组件中的缺陷。没有亲自检查实际代码,不要做任何假设。
7.5.2 Microsoft Script De b u g g e r
当开发更复杂的处理实际任务的应用程序时,经常需要一个更加强大的工具来进行调试。
Microsoft Script Debugger(微软脚本调试器 )是一种允许调试运行在客户机和服务器上的脚本的调试工具。它能用于调试任何用启用 A c t i v e X的脚本语言 (包括 V B S c r i p t和 J S c r i p t )编写的程序,也能够用来调试对 Java applet,Java Bean和 A c t i v e X组件的调用。
在研究这个工具之前,先简要说明一些问题。如前所述,A S P应用程序由两种脚本组成,
一种是客户端脚本,一种是服务器端脚本。 客户端脚本通常由 V B S c r i p t或 J S c r i p t脚本语句组成,
第 7章 调试和错误处理 计计 2 3 9下载当其到达客户端时出现在 H T M L页面中并在此执行,可能是在载入文档时或是在对一些事件的响应中。服务器端脚本通常也由 V B S c r i p t或 J S c r i p t语句组成。当浏览器请求网页时,服务器端脚本由 I I S执行。在下面的讨论中,将讨论服务器端脚本调试的方法。然而所讨论的许多技术也可用于客户端脚本调试。
1,服务器端的调试为了调试服务器端脚本,在运行 I I S的计算机上运行脚本调试器,然而在使用脚本调试器之前,必须启用调试。为了使性能最优化,基于 A S P的应用程序在缺省情况下关闭了调试功能。
注意,不要对生产性的应用程序 (即处于活动状态的并被他人使用的公用网站 )打开调试功能。这样会减慢整个应用程序的运行,并且错误能使网页出现不确定的停止运行情况。
调试仅能为虚拟应用程序和整个 We b网站进行设置,为了启用调试,打开应用程序或站点的 P r o p e r t i e s对话框,在 Home Directory选项卡中,点击 C o n f i g u r a t i o n按钮,在 A p p l i c a t i o n
C o n f i g u r a t i o n对话框的 App Debugging选项卡中,选择 Enable ASP server-side script
d e b u g g i n g”,如图 7 - 2 2所示。下面准备调试我们的应用程序。
图 7-22 启用调试的屏幕注意 Application Configuration对话框包含一个复选框,能够启用客户端脚本调试。这一点在 IIS 5.0中没有实现,在文档中仅标记为,reserved for future use” 。如果通常的 5 0 0 -
1 0 0,a s p定制错误页面不可用,Script Error Messages部分中包含将文本。
(1) 处理服务器脚本不像客户端脚本,基于 A S P的应用程序脚本不是事件驱动的。当客户端要求一个来自服务器的网页时,服务器读取网页内容,并处理所有的服务器脚本 (即在 < %,,,,% >和 < S C R I P T
R U N AT= " S E RV E R " > < / S C R I P T >段中的所有内容 ),也包括在 H T M L文本中的“行内”脚本段
240计计 ASP 3 高级编程 下载内容,例如:
The valne of the result is,<% = strResult %>
处理流程显示在图 7 - 2 3所示的框图中。
当 I I S载入网页时将处理 A S P页面中的所有脚本,在任何输出送给客户端之前,A S P及脚本引擎能够捕获语法和运行期错误 (除非你关闭缓冲或调用 R e s p o n s e,F l u s h方法 )。
(2) 脚本调试器提供的帮助启用脚本调试时,如果出现错误,在服务器屏幕上可以看到一个描述 A S P代码错误的对话框,
点击 O K,然后调入当前 A S P网页的一个只读拷贝,
打开的脚本调试器,错误出现的行由箭头指示,
如图 7 - 2 4所示。
图 7-24 脚本调试器这里,错误的产生是由于出现了 Page Counter对象方法的名字错误,应是 D o P a g e H i t而不是 P a g e H i t。同时,脚本调试器找到了错误并且终止了页面的运行,工具条上的按钮用于程序的继续运行、单步程序运行或者终止页面的处理。
工具条最右边的按钮打开脚本调试器中的 I m m e d i a t e窗口,可以用它和页面进行交互,并且很可能找到出错的地方。例如,可以查询或者设置变量值或组件属性,可以执行内部函数和子程序、自定义函数和子程序以及已经创建的对象方法等。在图中,调用了 Page Counter组件的 P a g e H i t方法,然后查询 H i t s属性以得到正在运行的脚本中该处的值。
为了了解为什么在“公共”网站上不应使用脚本调试器,可以从客户机上打开一个包含服务器端错误的页面。在这种情况下,错误信息对话框出现在服务器上,
脚本调试器也在服务器上打开。在客户机上,直到运行在服务器上的脚本调试器关闭,才开始载入该页面。
(3) 启动和使用调试器启用脚本调试后,虚拟应用程序的网页中出现错误时,脚本调试器自动启动。还可以人第 7章 调试和错误处理 计计 2 4 1下载图 7-23 服务器脚本运行流程图
ASP
ASP 引擎错误?否是
ASP代码
HTML
ASP代码 错误消息脚本调试器工启动脚本调试器,在 Windows 2000的 S t a r t菜单 (Programs|Accessories|Microsof Script
D e b u g g e r )中完成。相应地,也可在想打开脚本调试器的地方把一个 S t o p语句插入 A S P程序中,
当运行至 S t o p语句时,I I S会终止 A S P程序的执行,启动脚本调试器,显示当前页面并指出含有 S t o p语句的当前行。
脚本调试器能完成下列工作:
查看正在或已经运行的文档的列表,并从中选择一个进行查看或编辑。
在打开的网页中设置一个新断点,页面在该点停止运行以便进行调试。
单步调试,一步运行一条语句,可选地执行子程序和函数。
查看调用栈 (Call Stack),显示程序中在该点被调用的嵌套子程序或函数。
2,脚本调试器的技巧和窍门下面是使用 Mircorsoft Script Debugger时,有助于找到脚本中错误的一些窍门。
如果调试服务器端脚本,为 A S P应用程序启用脚本调试器。否则,错误信息将作为文本传送给客户端的浏览器,并且不能对服务器端脚本使用脚本调试器。
调试完成后,关闭调试功能,否则会降低服务器性能,并且错误的页面会停留在客户端。
对于一个或更多的 A S P应用程序,如果启用脚本调试器,将传送给它所有的服务器错误,
包括那些远程客户访问网页时出现的错误。因此,除非能在自己的服务器上调试,否则不要启用脚本调试器。
如果在一个没有安装在服务器上的浏览器中工作,并且在网页中显示错误,则错误在服务器端脚本中。如果一个错误信息出现在对话框中,则错误在客户端脚本中。
如果在,a s p文件中有一个语法或运行期错误,并且已经对这个 A S P应用程序启用调试功能,客户端浏览器将不显示语法错误 (除非浏览器运行在服务器上 ),仅显示超时或不能打开网页。
在表明服务器端脚本中是否有错误的消息中,显示的行号指的是包含这个错误的,a s p文件的相应行。
如果在由,a s p文件创建的客户端脚本中有错误,行号并不指向,a s p文件的错误行,而是指向错误出现的,a s p文件的 H T M L输出行。为了查看这行,应在客户浏览器中查看
H T M L文件的源程序。
VBScript和 J S c r i p t错误代码在附录 D中。
7.5.3 获得 A S P的帮助和支持如果遇到一个不能处理的错误,或者看来像 A S P中的一个,b u g”的事情,最好能够寻求帮助以解决这个问题。关于 A S P在 We b上有许多有用的信息源,第 1章后面我们列举了许多。
但是,对一些特殊问题,确实需要一些更直接的帮助。
在计算机上安装的 A S P 和 I I S 文档是一个好起点,并且能通过浏览器的 U R L 为
h t t p,/ /y o u r s e rv e r n a m e/iishelp/ 进行访问。运行 Windows 2000的附加组件设置或主设置程序 (依赖于安装的 Windows 2000版本 )时,应保证安装了全部的文档。
也可以从,Microsoft for Windows 2000”得到的完整平台 S D K,其中包含了大量的关于
Wi n d o w s和 Windows 2000中 I n t e r n e t服务的附加信息。它包含完整的 V B S c r i p t和 J S c r i p t参考。
242计计 ASP 3 高级编程 下载它可以微软获得,并提供给 M S D N成员。脚本参考文档可单独获得,也可以从,h t t p,/ / w w w.
m i c r o s o f t,c o m / s c r i p t i n g/”网站下载。也可从这里获得脚本调试器。
微软开发者网络 (The Miorosoft Developer's Network,MSDN) We b站点也提供了许多支持和帮助,即使这部分信息有时难以找到。还可以从 Wo r k s h o p网站 ( h t t p,/ / m s d n,m i c r o s o f t,
c o m / w o r k s h o p / )开始,这个网站在左边导航栏中有很好的索引和一系列标题。
另外,位于 http://msdn.microsoft.com/Library/default.htm 的主 M S D N库包含有文章、基础知识,FA Q和其他用于 I I S和 A S P的支持材料,左边窗口使用一个 J a v a扩展列表控件,使用户很容易进行查找。
如果需要特别的帮助,或者需要向其他开发者提出一些问题,在 m s n e w s,m i c r o s o f t,c o m网站上有一些有用的新闻组。还可以订阅 m i c r o s o f t,p u b l i c,i n e t s e r v e r,i i s,m i c r o s o f t,p u b l i c,
i n e t s e r v e r,a c t i v e s e r v e r p a g e s和 m i c r o s o f t,p u b l i c,i n e t s e r v e r,i i s,m i s c。一些 ASP We b网站也提供有关 A S P方面的讨论话题、论坛或聊天室。
7.6 小结本章讨论的内容是大多数编程者最不喜爱的工作。即使最简单的脚本,也不可能就能第一次正确地工作。随着 A S P提供越来越多的特性,在脚本中出现错误的机会也增加了。了解如何发现并处理错误的相关基本知识,是非常必要的。
通过分析可能出现的不同种类的错误,弄清楚缺省的 A S P和脚本引擎错误处理系统捕获错误的机理,有助于我们更容易地跟踪错误。随着 A S P的成功使用,A S P脚本和运行环境更复杂,产生错误的可能性也提高了。
在研究错误是什么和来自哪里的同时,也介绍了一些预防性编程的方法以便能尽早地发现问题,防止把错误和无效数据传给其他的应用程序。编程时出现的错误越少,越容易发现和解决它们。
然而,好的编程习惯并不能阻止某些种类的错误发生,例如那些由外部资源和服务造成的错误。这意味着提供自己的定制错误处理代码,在出现错误时知道如何跟踪错误并进行妥善处理,是非常重要的。
最后,以对 Microsoft Script Debugger的阐述结束了本章,它是有助于找到和解决网页中的运行期错误的一个有用工具。它可以暂停程序执行和进行单步执行,同时还能够观察程序在进行什么,甚至能够和脚本进行交互。
因此,本章主要覆盖如下内容:
能够出现的错误的类型。
如何防止各种错误出现。
如果不能防止错误发生,如何妥善处理错误。
如何发现和处理脚本错误及其他类型的错误。
如何使用定制错误页面获得错误信息。
如何记录发生的错误以监视我们的网站。
本书的下面章节将回过头来再次讨论服务器组件。我们将深入讨论 ActiveX Data
O b j e c t s ( A D O )组件,并熟悉如何使用 A D O访问数据库和各种类型的数据存储。
第 7章 调试和错误处理 计计 2 4 3下载