帝国软件
  设为首页 加入收藏 关于我们
 
解密帝国网站管理系统
栏 目:
 
您的位置:首页 > 技术文档 > ASP编程
处理错误
作者:佚名 发布时间:2005-04-02 来源:不详
     即使采用了防御性编程技术之后,错误仍能进入到网页,这可能是因为测试并不充分,或者是因为所依靠的一些其他资源或服务没有正确工作。为了防止页面出现问题,在程序中要能够进行定制错误处理。

7.4.1 ASP缺省错误处理器
       前面已经看到过,ASP和IIS能找出网页中的大多数错误,并且能自动生成错误信息页,这些错误几乎总是500.100类型的,并且IIS用Server.Transfer方法装载以500-100.asp命名的缺省错误页,然后传送给客户。第4章介绍了这一工作过程,以及如何与定制错误网页接口。
       然而,运行期脚本错误不总是由IIS发现的,当一个运行期错误发生时,脚本引擎会查看一下目前执行点或语句的环境。如果正在执行一个子程序或函数,缺省的脚本引擎错误处理器通过终止子程序的运行并返回调用子程序的地方来指出错误。
       在这里,程序会查看是否实现了其他的错误处理器,如果没有的话,又会重复这个过程,然后返回到调用子程序的地方。当子程序返回到网页的主程序(在任何其他子程序或函数外面)时,程序又查看是否实现了任何其他的错误处理器。在这个过程中,只有确实没有发现其他的错误处理器,程序才给ASP提示错误,指示IIS把执行转到缺省的错误页面。
7.4.2 VBScript错误处理
       在VBScript中,可以使脚本解释器不处理其找到的任何错误,并且使用On Error Resume Next语句继续运行下个语句。一旦这个语句已被处理,脚本引擎将继续运行后面的程序,而不理会已经发现的任何错误。然而,这种过程仅适用于顺序执行语句的环境,换句话说,不适用于嵌套的函数或子程序。
1.  使用On Error Resume Next语句
一个错误在子程序中出现时,如果没有运行On Error Resume Next语句,那么错误将被交给调用它的环境,这个过程一直重复到找到运行On Error Resume Next语句的环境继续运行,或者找到缺省的脚本错误处理器,把错误交给ASP并且IIS显示缺省错误网页。这个过程如图7-16所示:

这种错误调用链意味着可以创建防止使程序停止运行的运行期错误的函数和子程序。如果在子程序的开头放置一个On Error Resume Next语句,任何运行期错误会中止这个子程序的运行,但是调用该子程序的程序将继续运行而不会引起网页的停止。
例如,如果需要向一个文件中写入字符串,可以通过一个独立的函数对文件进行访问文件,防止错误中断整个程序的运行:
' create a file named strFileName, overwriting any existing one with that name
' and writes strContent into it then closes the file
' returns True if it succeeds, or False on any error
Function WriteNewFile(strFileName, strContent)
       On Error Resume Next         ' turn off the default error handler
       WiteNewFile = Flase             ' default return value of function
       Set objFSO = CreateObject("Scripting.FileSystemObject")
       If Err.Number = 0 Then Set objFile = objFSO.CreateTextFile(strFileName, True)
       If Err.Number = 0 Then objFile.WriteLine strContent
       If Err.Number = 0 Then objFile.Close
       If Err.Number = 0 Then WriteNewFile = True
End Function
注意上面的程序在试图处理每个程序语句之前,先检查VBScript的Err对象的Number属性。如果这个值为0(还没有出现错误),那么就能够继续对文件的定入和创建过程。然而如果错误确实发生了,脚本引擎将设置Err对象的属性的值,并且继续处理下一行。
只要不引起错误而能正常运行,函数的返回值将设置为“True”。否则函数将返回“False”。在编程中可以在对其进行测试以后,再使用该函数和采取其他行动。
下面是一个简单的例子,我们希望对任务的第一部分采用一个独立的函数,以便能更精确地辨别出错误产生在何处。这样,调试时也更容易阅读代码。在页面的主程序中,可以调用三个单独的函数。
If CreateNewFile(strFileName) Then                         ' create the new file
       Response.Write "New file successfully created<BR>"
       If WriteContent(strContent) Then                       ' write the content
              Response.Write "Content written to file<BR>"
       Else
              Response.Write "ERROR: Failed to write to the file<BR>"
       End If
       If CloseFile(strFileName) Then
              Response.Write "File closed<BR>"
       Else
              Response.Write "ERROR: Failed to close the file<BR>"
       End If
Else
       Response.Write "ERROR: Failed to create the new file<BR>"
End Funciotn
2.  使用On Error Goto 0
在ASP 2.0(尽管没有文档记录)和ASP 3.0中,也能使用On Error Goto 0语句恢复缺省的错误处理行为。在运行这个语句后,发生的运行期错误将导致缺省错误处理,在环境链中检查每个嵌套的程序,直到主页面代码。如果没有其他的环境关闭缺省错误处理,网页的执行将停止并显示IIS缺省错误网页。
3.  VBScript Err对象
在前面的例子中,关闭缺省错误处理时,通过检查VBScript Err对象的Number属性,查看错误是否已经出现。Err对象存储了关于运行期错误的信息,表7-3和表7-4给出了VBScript Err对象提供的方法和属性。
表7-3  VBScript Err对象的方法
方  法
说  明

Clear
清除当前所有的Err对象设置

Raise
产生一个运行期错误


表7-4  VBScript Err对象的属性
属  性
说  明

Description
设置或返回一个描述错误的字符串

Number
(缺省)设置或返回指定一个错误的值

Source
设置或返回产生错误的对象的名称

使用这些属性可以检查发生了哪种错误。例如,可以根据错误号采取不同的措施,也可以用Source和Description的属性值为用户提供错误信息,或者传送到一个文件中。
也可以使用Err对象生成一个错误。为什么要做这些呢?因为有时想把一个定制的错误消息传送给用户。可以把Err对象的属性设置成所希望的任何值。然后调用Raise方法来产生这种错误,这样做会停止程序的运行,并且把错误沿调用链向回传递。
下面的例子显示了在服务器磁盘上读取一个文本文件时,如何处理错误。注意如何使用常数vbObjectError,以确定所选择的错误号不会和一个已存在的错误号混淆。通过把任意选择的错误号加到此常数中,就能够保证和预定义的错误不混淆。
Functoin ReadThisFile(strFileName)            ' returns the content as a string
       On Error Resume Next
       ReadThisFile = " "                       ' default return value of function
       Set objFSO = CreateObject("Scripting.FileSystemObject")
       Set objFile = objFSO.OpenTextFile("strFileName", ForReading)
       Select Case Err.Number
              Case 0                                        ' OK, take no action
              Case 50, 53                                ' standard file or path not found errors
                     ' create custom error values and raise error back up the call chain
                     intErrNumber = vbObjectError + 1073        'custom error number
                     strErrDescription = "The file has been deleted or moved. "
                     strErrSource = " ReadThisFile function"
                     Err.Raise intErrNumber, strErrSource, strErrDescription
                     Exit Function
              Case Else                                    ' som other error
                     ' raise the standard error back up the call chain
                     Err.Raise Err.Number, Err.Source, Err.Description
                     Exit Function
       End Select
       ReadThisFile = objFile.ReadAll             ' we opened it OK, so return the content
       objFile.Close
End Function
调用这个函数的代码可以使用On Error Resume Next语句,并且能捕获这个函数产生的错误。
On Error Resume Next
strContent = ReadThisFile("myfile,txt")
If Err.Number = 0 Then
       Response.Write "File content is:<BR>" & strContent
Else
       Response.Write "Err.Source & "<BR>" & Err.Description
End If

7.4.3 JScript错误处理
       在5.0版之前,JScript的错误处理处理能力并不出色,然而在5.0版中情况改变了,JScript采用了一套和Java以及C++非常类似的错误处理系统。它掌握起来尽管不像VBScript技术那样容易,但人们认为在错误处理上,JScript走在前头。
       在第1章中,在讨论这两个主要脚本语言的新特点时候,已详细讨论了JScript错误处理,这里不再重复。如果阅读第1章时跳过了这部分,可以回到那里看看。
7.4.4 使用IIS错误页面
       与ASP错误处理过程相关的内容是为IIS提供可定制的错误页面。事实上,在IIS 4.0中也有这个特点。但新的ASP内置对象ASPError,更易于使用且提供更加强大的功能。
       在第4章,当我们研究Server.Execute和Server.Transfer方法时,已经讲述了如何建立定制的错误页面。我们也讨论和使用了ASPError对象,但这种方式受到了一定的限制。在这一部分,将介绍如何将定制的错误网页和ASPError对象结合起来建立一个更好的处理ASP错误的方法。
       我们可以使用VBScript检查ASPError对象的内容,从而创建一个定制的错误页面。构建一个包含错误内容全面信息的字符串,且写入到服务器磁盘上的日志文件中。然而网页的设计仅使访问者看到网页不可用这样一条信息是不行的,应该使访问者能够选择是重新载入上一个网页还是回到主页,使他们没意识已经发生了错误。
       尽管我们采用VBScript创建这个网页,但其使用的一些特性对JScript来说也是适用的,这两种脚本语言的相互转换也是比较容易的。
       可以从http://www.wrox.com站点下载本章及本书其他章节的示例文件。
1.  设置定制的错误页面
在能使用定制的错误页面之前,必须在Internet Services Manager进行相应的设置(设置方式见第4章)。把示例文件装入计算机的wwwroot目录中,打开Chapter07子目录的Properties对话框,在Custom Errors选项卡中,滚动列表并选中HTTP错误“500:100”条目,点击Edit Properties按钮,并键入定制的错误页面Custom_error.asp的URL,如图7-17所示:

现在Chapter07子目录中的页面出现一个ASP错误时,就会打开定制的错误页面。
2.  使用定制的错误页面
在浏览器中打开Chapter07目录并选择到“Using a Custom Error Page”的链接,这个页面显示了一系列用于产生各种类型的错误的按钮,点击标有“Load a Page with a Syntax error”的按钮,如图7-18所示:

这将载入一个名为syntax_error.asp的简单页面。然而看不到这个页面,因为这个页面包含了一个语法错误。ASP终止这个页面的编译/执行,并把执行转到定制错误页面,这个页面展示了错误的细节和两个按钮,这两个按钮用以返回上个页面(主菜单)或返回Web站点的缺省主页,如图7-19所示:

这个页面也把错误报告追加到服务器磁盘C:temp文件夹中名为custom_error.log的日志文件中,可以在文件编辑器中打开并查看它,图7-20所示的日志文件已经记录了几个错误。

如果在页面中得到了一个信息,指明日志文件不能写入信息,可能是因为IUSR_machinename(IUSR_计算机名)帐号没有访问C:temp目录的权限。当测试这个页面时,应该给予IUSR_machinename帐号对这个目录的全部控制权,或者改变custom_error.asp页面的程序代码以指向一个IUSR有全部控制权的文件夹
错误消息出现在页面中的唯一原因,是因为在cause_error.asp页面中我们选择了相应的复选框。如果关闭该选项并再次点击按钮,便看不到错误的详细情况,然而错误信息仍然记录在服务器磁盘上的custom_error.log错误日志文件中。
“Display debugging information”复选框给定制错误页面(而不是日志文件)提供了更多的信息,有助于调试那些使用ASP内置对象集合值的页面,如图7-21所示:

在本章下面部分,将再讨论这一问题,同时也可以了解“Cause An Error”页面上的其他按钮所提供的其他种类的错误信息。注意有一些按钮能够比其他的按钮能够提供更多信息。特别是只有最后一个按钮给出ASP错误代码的值(这里是ASP 0177)。
(1) “Cause An Error”页面的功能
与先前讨论的示例页面一样,引起错误的页面使用同样的技术,用<Form>把值提交给同一个页面。然后ASP程序查看窗口上点击的是那个SUBMIT按钮,然后运行代码的相应部分。同时查看是否页面上两个复选框是否选中,如果是这样,程序首先设置一个或两个会话级的变量以指明这一点。
<%
'see if we are displaying error and debug information
'set session variables to retrieve in the custom error page
If Len(Request.Form("chkShowError")) Then
  Session("ShowError") = "Yes"
Else
  Session("ShowError") = ""
End If
If Len(Request.Form("chkShowDebug")) Then
  Session("ShowDebug") = "Yes"
Else
  Session("ShowDebug") = ""
End If
...
%>
由于使用了Server.Transfer,当错误发生时,正在运行的网页的整个ASP环境由IIS传给定制错误页面。然而,脚本变量的值并没有传给定制错误页面,所以必须使用Session变量,或者把值添加到Request.Form或Request.QueryString集合以便把值传送给定制错误页面。
设置了Session变量之后,程序继续查看点击了哪个按钮。每个类型的错误(除了第一类型外),都是由运行相应的ASP代码产生的,第一类型的错误需要调用另一个页面。
...
'look for a command sent from the FORM section buttons
If Len(Request.Form("cmdSyntax")) Then
   Response.Clear
   Response.Redirect "syntax_error.asp"
End If
If Len(Request.Form("cmdParamType")) Then
   intDate = "error"
   intDay = Day(intDate)
End If
If Len(Request.Form("cmdArray")) Then
   Dim arrThis(3)
   arrThis(4) = "Causes an error"
End If
If Len(Request.Form("cmdFile")) Then
   Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
   Set objTStream = objFSO.OpenTextFile("does_not_exist.txt")
End If
If Len(Request.Form("cmdPageCount")) Then
   Set objPageCount = Server.CreateObject("MSWC.PageCounter")
   objPageCount.WrongProperty = 10
End If
If Len(Request.Form("cmdObject")) Then
   Set objThis = Server.CreateObject("Doesnot.Exist")
End If
%>
(2) 定制错误页面的工作
知道了如何创建错误后,让我们来看看定制的错误页面。在前面的章节里已经知道了构建网页需要的理论,这里再概要地描述一下其工作过程。第一步是关闭缺省的错误处理器以便页面程序不被另一个错误中断。第二步通过创建一个新的ASPError对象收集原始错误信息。进行这个工作时要格式化一些值,并把它们转换成合适的数据类型。
<%
'prevent any other errors from stopping execution
On Error Resume Next

'get a reference to the ASPError object
Set objASPError = Server.GetLastError()

'get the property values
strErrNumber = CStr(objASPError.Number) 'normal error code
strASPCode = objASPError.ASPCode        'ASP error code (if available)
If Len(strASPCode) Then
   strASPCode = "'" & strASPCode & "' "
Else
   strASPCode = ""
End If
strErrDescription = objASPError.Description
strASPDescription = objASPError.ASPDescription
strCategory = objASPError.Category      'type or source of error
strFileName = objASPError.File          'file path and name
strLineNum = objASPError.Line           'line number in file
strColNum = objASPError.Column          'column number in line
If IsNumeric(strColNum) Then            'if available convert to integer
   lngColNum = CLng(strColNum)
Else
   lngColNum = 0
End If
strSourceCode = objASPError.Source    'source code of line
...
现在构建一个错误报告字符串,这段程序看起来复杂,但实际上仅是一系列If ...Then语句的嵌套,用以产生良好的报告格式,没有任何空的段落。如果错误是语法错误,来自ASPError对象的Source属性的源代码可在strSourceCode变量中得到,可以使用这个变量及lngColNum的值(从ASPError对象的Column属性中得到)增加一个标记用来指明在源程序中的什么地方发现了错误。
...
'create the error message string
strDetail = "ASP Error " & strASPCode & "occurred " & Now
If Len(strCategory) Then
   strDetail = strDetail & " in " & strCategory
End If
strDetail = strDetail & vbCrlf & "Error number: " & strErrNumber _
          & " (0x" & Hex(strErrNumber) & ")" & vbCrlf
If Len(strFileName) Then
   strDetail = strDetail & "File: " & strFileName
   If strLineNum > "0" Then
      strDetail = strDetail & ", line " & strLineNum
      If lngColNum > 0 Then
         strDetail = strDetail & ", column " & lngColNum
         If Len(strSourceCode) Then
                     'get the source line so put a ^ marker in the string
            strDetail = strDetail & vbCrlf & strSourceCode & vbCrlf _
                      & String(lngColNum - 1, "-") & "^"
         End If
      End If
   End If
   strDetail = strDetail & vbCrlf
End If
strDetail = strDetail & strErrDescription & vbCrlf
If Len(strASPDescription) Then
   strDetail = strDetail & "ASP reports: " & strASPDescription & vbCrlf
End If
...
(3) 记录错误
用名为strDetail的字符串变量创建了错误报告后,可以像在第5章中做的那样,采用FileSystemObject对象把它追加到日志文件中。如果成功,布尔型“failed flag”变量将被设置成False。
...
'now log error to a file. Edit the path to suit your machine.
'you need to give the IUSR_machinename permission to write and modify
'the file or directory used for the log file:
strErrorLog = "c:tempcustom_error.log"
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
Set objTStream = objFSO.OpenTextFile(strErrorLog, 8, True)  '8 = ForAppending
If Err.Number = 0 Then objTStream.WriteLine strDetail & vbCrlf
If Err.Number = 0 Then
   objTStream.Close
   blnFailedToLog = False
Else
   blnFailedToLog = True
End If
%>
(4) 跳转到另一个页面
现在准备在网页中创建一些输出。在此之前,需要检查错误细节以确定下一步要做什么。例如,可用ASPError对象的Number或其他属性检查错误类型。在这里,可认为“Type Mismatch”错误不是代码中有错误,可能是由于用户在文本框中输入错误数据产生的。所以不显示这个网页的剩余部分,而是跳转到另一个网页
If objASPError.Number = -2146828275 Then            ' 0x800A000D - type mismatch
   Response.Clear
  Response.Redirect "/"                                           ' go to the Home page
End If
是否决定这样做依赖于你自己的情况以及你打算发现、记录或显示的错误类型。需要注意的是,因为我们不想把目前的网页环境传送到新的网页上,所以选择使用Reponse.Redirect语句而不是用Server.Transfer语句。
(5) 显示错误信息
最后,显示错误报告和其他信息以及返回到上一个网页或主页的按钮。
<%
'see if the logging to file failed
'if so, display message
If blnFailedToLog Then
   Response.Write "<B>WARNING: Cannot log error to file '" & strErrorLog & "'</B>.<P>"
End If

'see if we are displaying the error information
If Session("ShowError") = "Yes" Then
%>
   <PRE><% = Server.HTMLEncode(strDetail) %></PRE>
<%
End If

'see if we are displaying the debug information
If Session("ShowDebug") = "Yes" Then Server.Transfer "debug_request.asp"

'create the buttons to return to the previous or Home page
strReferrer = Request.ServerVariables("HTTP_REFERER")
If Len(strReferrer) Then
%>
   <FORM ACTION="<% = strReferrer %>">
   <INPUT TYPE="SUBMIT" NAME="cmdOK" VALUE="   ">
     Return to the previous page<P>
   </FORM>
<%
End If
%>
<FORM ACTION="/">
<INPUT TYPE="SUBMIT" NAME="cmdOK" VALUE="   ">
  Go to our Home page<P>
</FORM>
对上面这段程序需要注意的是:在定制错误页面里,不能使用Server.Execute方法。如果我们这样做的话,至少程序不能正常工作。当程序把执行转到特定的网页时,程序不会再返回到当前网页,这就是我们使用Server.Transfer方法载入显示调试信息的网页的原因。这是下一部分要讨论的问题。
  
评论】【加入收藏夹】【 】【打印】【关闭
※ 相关链接
 ·程序调试—发现及处理错误  (2005-04-02)
 ·事务处理的定义  (2005-04-02)
 ·在ASP中优化数据库处理  (2005-04-02)
 ·改进ASP应用程序中的字符串处理性  (2005-04-02)
 ·把@ENABLESESSIONSTATE设为false  (2005-04-02)
 ·ASP 中健壮的页结构的异常处理  (2005-04-02)
 ·ASP和SQL结合处理时间小解洞  (2005-04-02)
 ·ASP中健壮的页结构的异常处理  (2005-04-02)
 ·ASP.NET中的错误处理支持  (2005-04-02)
 ·在ASP.NET中进行文件处理  (2005-04-02)

   栏目导行
  PHP编程
  ASP编程
  ASP.NET编程
  JAVA编程
   站点最新
·致合作伙伴的欢迎信
·媒体报道
·帝国软件合作伙伴计划协议
·DiscuzX2.5会员整合通行证发布
·帝国CMS 7.0版本功能建议收集
·帝国网站管理系统2012年授权购买说
·PHPWind8.7会员整合通行证发布
·[官方插件]帝国CMS-访问统计插件
·[官方插件]帝国CMS-sitemap插件
·[官方插件]帝国CMS内容页评论AJAX分
   类别最新
·在ASP中使用数据库
·使用ASP脚本技术
·通过启动脚本来感受ASP的力量
·学习使用ASP对象和组件
·解析asp的脚本语言
·初看ASP-针对初学者
·ASP开发10条经验总结
·ASP之对象总结
·ASP与数据库应用(给初学者)
·关于学习ASP和编程的28个观点
 
关于帝国 | 广告服务 | 联系我们 | 程序开发 | 网站地图 | 留言板 帝国网站管理系统