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所示:
圖7-17 Custom Errors選項卡 現在Chapter07子目錄中的頁面出現一個ASP錯誤時,就會打開定制的錯誤頁面。 2. 使用定制的錯誤頁面 在瀏覽器中打開Chapter07目錄并選擇到“Using a Custom Error Page”的鏈接,這個頁面顯示了一系列用于產生各種類型的錯誤的按鈕,點擊標有“Load a Page with a Syntax error”的按鈕,如圖7-18所示:
圖7-18 演示定制錯誤頁面的屏幕1 這將載入一個名為syntax_error.asp的簡單頁面。然而看不到這個頁面,因為這個頁面包含了一個語法錯誤。ASP終止這個頁面的編譯/執行,并把執行轉到定制錯誤頁面,這個頁面展示了錯誤的細節和兩個按鈕,這兩個按鈕用以返回上個頁面(主菜單)或返回Web站點的缺省主頁,如圖7-19所示:
圖7-19 演示定制錯誤頁面的屏幕2 這個頁面也把錯誤報告追加到服務器磁盤C:\temp文件夾中名為custom_error.log的日志文件中,可以在文件編輯器中打開并查看它,圖7-20所示的日志文件已經記錄了幾個錯誤。
圖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所示:
圖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對象收集原始錯誤信息。進行這個工作時要格式化一些值,并把它們轉換成合適的數據類型。 <% '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:\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 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方法載入顯示調試信息的網頁的原因。這是下一部分要討論的問題。
7.5 程序調試——發現及處理錯誤 讀完上面內容,讀者一定很想創建一個沒有錯誤的ASP網頁。但你可能會發現網頁并不能工作。怎么辦,只有進行測試。 在這一部分,首先簡要看一下能使調試更容易的一些工具。Microsoft Script Debugger試圖把調試支持工具提高到像Visual Basic、Delphi和Visual C++等大多數傳統編程環境的水平。然而,下面將首先討論一些更傳統的有助于跟蹤出現在網頁中的錯誤的技術。
|