图7-17 Custom Errors选项卡 现在Chapter07子目录中的页面出现一个ASP错误时,就会打开定制的错误页面。 2. 使用定制的错误页面 在浏览器中打开Chapter07目录并选择到“Using a Custom Error Page”的链接,这个页面显示了一系列用于产生各种类型的错误的按钮,点击标有“Load a Page with a Syntax error”的按钮,如图7-18所示:
图7-21 cause_error.asp页面的选择框 在本章下面部分,将再讨论这一问题,同时也可以了解“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对象收集原始错误信息。进行这个工作时要格式化一些值,并把它们转换成合适的数据类型。 <% 'divvent 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:\temp\custom_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 divvious or Home page strReferrer = Request.ServerVariables("HTTP_REFERER") If Len(strReferrer) Then %> <FORM ACTION="<% = strReferrer %>"> <INPUT TYPE="SUBMIT" NAME="cmdOK" VALUE=" "> Return to the divvious page<P> </FORM> <% End If %> <FORM ACTION="/"> <INPUT TYPE="SUBMIT" NAME="cmdOK" VALUE=" "> Go to our Home page<P> </FORM> 对上面这段程序需要注意的是:在定制错误页面里,不能使用Server.Execute方法。如果我们这样做的话,至少程序不能正常工作。当程序把执行转到特定的网页时,程序不会再返回到当前网页,这就是我们使用Server.Transfer方法载入显示调试信息的网页的原因。这是下一部分要讨论的问题。