VBScript 不支援現代語言的 try/catch/finally 結構,而是透過 On Error 語句與全域 Err 物件實現錯誤處理。本文系統整理三種 On Error 模式、Err 物件屬性/方法、最佳實踐模式與常見陷阱,幫助維護舊版 ASP、WSH 腳本的開發者寫出健壯代碼。
| 語句 | 行為 | 適用場景 |
|---|---|---|
On Error Resume Next | 發生執行錯誤時,**跳過錯誤行**,繼續執行下一行。錯誤資訊存入 Err 物件。 | 預期可能失敗的單行操作(檔案讀寫、COM 物件呼叫、資料庫查詢)。 |
On Error GoTo 0 | **關閉**目前程序的錯誤處理,恢復預設行為:發生錯誤即終止腳本並顯示錯誤訊息。 | 在 Resume Next 區塊結束時,恢復嚴格模式。 |
On Error GoTo <label> | 跳轉到同一程序內的標籤(label:)。注意:VBScript **不支援**此語法,會編譯錯誤。僅 VB/VBA 支援。 | 不適用於 VBScript。 |
On Error Resume Next
Dim objFSO, objFile
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\nonexist.txt", 1) ' 讀取模式
If Err.Number <> 0 Then
WScript.Echo "錯誤 " & Err.Number & ": " & Err.Description
Err.Clear ' 重要:清除錯誤狀態,避免污染後續判斷
End If
On Error GoTo 0
| 成員 | 型別 | 說明 |
|---|---|---|
| Number | Long | 錯誤代碼(0 表示無錯誤)。VBScript 錯誤碼為正數;COM 元件可能回傳負數(如 0x800Axxxx)。 |
| Description | String | 人類可讀的錯誤描述。 |
| Source | String | 產生錯誤的物件/元件名稱(如 "Microsoft VBScript runtime error")。 |
| HelpFile | String | 說明檔路徑(可自訂)。 |
| HelpContext | Long | 說明檔主題 ID(可自訂)。 |
| Clear() | Method | 重設所有屬性為預設值(Number=0)。 |
| Raise(number, source, description, helpfile, helpcontext) | Method | 主動拋出錯誤,模擬錯誤發生。 |
' 定義自訂錯誤碼 (建議用 513 以上避免衝突)
Const ERR_DB_CONN = vbObjectError + 513
Function ConnectDB(connStr)
On Error Resume Next
Dim conn
Set conn = CreateObject("ADODB.Connection")
conn.Open connStr
If Err.Number <> 0 Then
Err.Raise ERR_DB_CONN, "ConnectDB", "資料庫連線失敗: " & Err.Description
End If
On Error GoTo 0
Set ConnectDB = conn
End Function
' 呼叫端
On Error Resume Next
Set db = ConnectDB("Provider=SQLOLEDB;...")
If Err.Number = ERR_DB_CONN Then
WScript.Echo "自訂錯誤: " & Err.Description
' 可選:記錄到事件日誌、發送郵件等
End If
On Error GoTo 0
On Error Resume Next,隨後立即 On Error GoTo 0。Err.Clear,否則 Err.Number 保持非零,導致後續判斷誤以為發生錯誤。Err.Number <> 0,應針對預期錯誤碼處理,其他錯誤向上拋或記錄。Err.Number & "|" & Err.Source & "|" & Err.Description 寫入日誌檔。| 陷阱 | 現象 | 對策 |
|---|---|---|
| 忘記 Clear | 後續正常代碼被誤判為錯誤 | 習慣:If Err Then ... Err.Clear |
| 全域 Resume Next | 所有錯誤被靜默吞沒,腳本「成功」但結果錯誤 | 嚴禁在腳本頂部直接 On Error Resume Next |
| COM 物件回傳 HRESULT | Err.Number 為負數 (如 -2147217887) | 用 Hex(Err.Number) 查閱文檔,或 Err.Number And &HFFFF 取低字 |
| 語法錯誤無法捕捉 | On Error 只捕捉**執行時**錯誤,語法錯誤會直接終止編譯 | 開發階段用編輯器語法檢查、測試腳本 |
| Err.Raise 後未清除 | 自訂錯誤殘留影響後續邏輯 | Raise 後立即 On Error GoTo 0 或由呼叫端 Clear |
' ===== 模板:安全執行高風險操作 =====
Function SafeExecute(riskyFunc, defaultValue)
On Error Resume Next
Dim result
result = riskyFunc()
If Err.Number <> 0 Then
LogError "SafeExecute", Err.Number, Err.Description, Err.Source
Err.Clear
result = defaultValue
End If
On Error GoTo 0
SafeExecute = result
End Function
Sub LogError(context, num, desc, src)
Dim fso, logFile
Set fso = CreateObject("Scripting.FileSystemObject")
Set logFile = fso.OpenTextFile("error.log", 8, True) ' 8=ForAppending
logFile.WriteLine Now & " | " & context & " | " & num & " | " & src & " | " & desc
logFile.Close
End Sub
' ===== 使用範例 =====
Dim connStr, conn
connStr = "Provider=SQLOLEDB;Data Source=.;Initial Catalog=Test;Integrated Security=SSPI"
Set conn = SafeExecute(Function()
Dim c: Set c = CreateObject("ADODB.Connection")
c.Open connStr
Set SafeExecute = c
End Function, Nothing)
If conn Is Nothing Then
WScript.Echo "資料庫連線失敗,請檢查 error.log"
Else
WScript.Echo "連線成功"
conn.Close
End If
新專案建議直接使用 PowerShell,擁有完整 try/catch/finally、throw、$Error 自動變數、結構化例外類型(System.Exception 衍生),除錯與維護效率遠優於 VBScript。
掌握 On Error Resume Next + Err 物件的正確用法,能在必須維護 VBScript 專案時,將錯誤處理從「靜默失敗」提升為「可控、可追蹤、可恢復」。