Error Handlers 的錯誤分類

不論是在開發還是佈署後的環境無可避免地總是會遇到 bug,所以軟體工程師時常在踩坑。為了在軟體報錯時,能迅速地找到問題點,Error Handler 就扮演了很大的角色,決定在 log 中應該要顯示的錯誤訊息。好的錯誤訊息能夠讓工程師快速找到問題發生的源頭,而模糊的錯誤資訊反而容易造成問題的發散,進而導致浪費了大量的時間在除錯。


引言

在撰寫錯誤處理 (Error Handlers) 時,不管是使用哪種語言,或無論是在應用軟體的前端、後端,又或是在韌體的撰寫時,軟體工程師都需要針對可能發生的錯誤進行處理。舉一個普遍的例子,在資料傳送的過程中,可能會遇到資料傳送成功、傳送失敗、延遲或沒有回應等幾種情況。在撰寫錯誤處理時,適合針對不同的運行環境、錯誤情境等做分類和程序調整。


如何分類錯誤

開發環境 (Development) 和正式環境 (Production) 的錯誤訊息

正式環境的錯誤資訊內容需要經過包裝: 不建議開發環境和正式環境在同樣的功能或方法中顯示相同的錯誤資訊,因為正式環境通常是直接開放給一般使用者來操作,所以有些太詳盡的資訊 (通常包含隱私內容) 可能會被有心人利用,導致軟體的破口。因此會將正式環境的錯誤顯示資訊盡量減少,只留下必要且不會洩漏隱私的內容;而在開發環境中,使用者基本上就是軟體開發者本身,所以錯誤訊息越詳細越容易能在開發階段就直接找到問題點。


操作錯誤 (Operational error) 和程式設計錯誤 (Programming error)

程式設計錯誤很常出現在開發階段,也有一些錯誤是在正式環境中出現,像是因為測試內容不完整沒提早發現錯誤的情況。一般程式設計上的錯誤是由於程式邏輯不對和語法上撰寫的錯誤而導致 bug 發生。相比於無法預料程式碼 bug 發生的程式設計錯誤,操作上的錯誤大多是可以預期的,例如我們能預期使用者可能因為某些不當操作導致軟體平台報錯: 像是表單未填寫完、輸入錯誤的訂單編號、伺服器因請求過多而超過負荷等。既然可以預期到會發生的問題,就能針對已知的錯誤去定義錯誤訊息要顯示的內容。


客戶端 (Client side) 的錯誤或是伺服器端 (Server side) 的錯誤

操作錯誤又可以再往下細分為兩個主要種類: 客戶端錯誤和伺服器端錯誤。在撰寫錯誤處理程序時,若是只拋出很籠統的 “系統出現錯誤” 這句話,其實很難透過這項訊息找到問題端點,並且還需要做額外的功夫先判斷是哪一邊出了問題。以網路世界中常見的 HTTP 請求來說,他也是將 HTTP 的回應狀態做分類,例如回應狀態碼是四百開頭 (4xx) 的就是表示是用戶端的錯誤;當回應狀態碼是五百開頭 (5xx) 意指錯誤發生在伺服器端。這樣一來就能用編號快速判斷發生錯誤的地方位在哪一邊。

一般而言,若是在網路的應用程式中,用戶端普遍會出現的錯誤是資料輸入錯誤: 密碼錯誤、id 不正確、名稱重複、資料格式不對等情形;伺服器端常出現的錯誤情境則是: 正在維護、超過負載、資料庫連線錯誤等。通常可預期客戶端會出現的錯誤會使用客製的錯誤處理程序 (custom errror handler) 來應對,盡量客製錯誤訊息以利於使用者能理解。由於客戶端出現的錯誤大多需要由使用者本身來修正,所以顯示的錯誤訊息需要能被使用者看得懂,也能了解到問題所在。


同步與非同步的錯誤處理

錯誤處理程序在同步和非同步的處理寫法上有一點不一樣,就是在處理的順序上。由於同步的錯誤發生是立即的,所以能直接往下執行錯誤程序,然而,非同步的錯誤通常會需要一些時間的等待,當等到抓到錯誤的當下,再回頭呼叫函式,來將錯誤訊息傳送出去。以 Express.js 來說,非同步的錯誤處理需要呼叫 next(error) 來將訊息傳遞給錯誤處理的 middleware,否則 Express.js 不會自動捕捉這些錯誤;而同步錯誤不需要呼叫 next() 就可以直接被 Express.js 自動捕捉並傳遞給錯誤處理 middleware。



上面講述了一些主要大宗的分類,以及為何要分類處理的原因和其重要性。當然有些開發者也有可能將錯誤種類再往下拆分,包含閘道器錯誤、資料庫錯誤等多種情況,不論分類方式為何,主要目的都是為了能快速找出問題發生源。錯誤種類的部分就先寫到這,接下來想提一下錯誤處理的技術文件編寫,因為錯誤處理的分類也應該要記錄下來。


錯誤處理文件撰寫

錯誤處理並非只有編寫程序本身而已,錯誤處理的技術文件撰寫也相當重要。這份技術文件能讓後續維護軟體的開發者以及軟體測試者能有個依循參考,也是日後不小心發生錯誤時能夠核對找出錯誤根源的依據。那麼錯誤處理的技術文件應該要包含哪些重點資訊呢?

> 錯誤類型與分類:
列出所有有定義出可能出現的錯誤,像是授權錯誤、驗證錯誤、伺服器錯誤等。
> 錯誤格式:
顯示錯誤回傳的結構和資料格式,例如 HTTP 狀態碼、錯誤訊息等內容。錯誤訊息的資料格式需要一致,方便前端在處理錯誤回應。
> 日誌紀錄:
說明錯誤如何被紀錄和紀錄的位置,以及紀錄的規範。
> 錯誤處理流程:
描述錯誤如何被捕捉、傳遞與處理。若是使用框架的 middleware 也可以附上此 middleware 的流程圖。

至於更進階的細節內容: 像是明確定義錯誤責任歸屬要由前端 / 後端處理、顯示在客戶端的錯誤訊息是否支援多國語言等。另外,要特別注意的是避免洩漏敏感資訊,像是不將內部錯誤細節 (如資料庫結構、堆疊追蹤) 資訊直接回傳給用戶。


小結

錯誤處理能探討的細節其實很多,這篇先以錯誤的主要分類來探討,當然這些大分類依據不同的軟體情境也能再往下拆分。錯誤分得越細,錯誤處理程序就能在第一線先把問題抽絲剝繭,後續工程師要找到問題根源就相對容易許多,相當於透過錯誤分類盡量縮小搜查面積,就能在問題發生時爭取到一些時間。雖然還是會發生無法預料的錯誤,但是每一次這些出其不意的錯誤若記錄下來,加入到錯誤處理的分類中,相信下一次的危機處理就會快很多。


Reference

Distinction Between Operational And Programmer Error in Nodejs
Difference between Operational and Programmer Errors
Error Handling in JS
Error Handling in Node.js



Author

Vian

Posted on

2025-06-27

Updated on

2025-07-28

Licensed under

Comments