API 發生錯誤時該怎麼顯示提示?
討論的專案是使用 toast 做 API 錯誤提示,所以討論範圍都會聚焦在顯示多個 toast 是否是好的?如何管理 toast?暫不思考使用 toast 是不是正確的。
前言
「希望在載入畫面時,假如同時有多支 API 出現錯誤,可以只顯示一個錯誤訊息就好。」 這是某位主管在例行會議上希望前端做到這件事情。
姑且先不論他的目的是什麼,主要是想藉這個機會想一想錯誤提示這件事情。
到目前為止,當前專案不管是 PM 還是 UI 還是其他相關人士都沒有針對這件事情設計,那麼到底該顯示什麼內容對使用者來說才是合適的呢?
我希望可以從目的、數量;從開發者、UX 來聊聊這件事。
錯誤提示的目的
我認為錯誤提示的觀看者可以分成:使用者、開發者。
使用者想透過錯誤提示知道:哪裡出了問題、可能的原因,以及接下來可以怎麼做。 開發者想透過錯誤提示知道:哪裡錯了、錯的原因。
雖然看起來一樣,但是開發者想知道的訊息不見得適合揭露給使用者。
例如開發者可能需要錯誤代碼或診斷紀錄來追查問題,使用者比較需要知道受到什麼影響、接下來可以怎麼做。使用者看得到的錯誤內容應足以協助處理問題,同時避免揭露敏感資訊和除錯細節。
錯誤提示的數量
一個畫面在載入時顯示多個錯誤訊息會有什麼問題嗎?
以 UX 角度來說,使用者可能會被一下子這麼多錯誤訊息嚇到,覺得你這網頁怎麼一堆問題。也可能來不及一口氣看完全部,知道可以怎麼因應這些錯誤。
以開發端來說,直接顯示每個錯誤可能是比較直覺的處理方式,不過也要考慮重複提示和使用者能否理解。
所以看起來應該先討論 UX 是否合理,再來看看如何實作才是對的。
先決定 UX
如果能先判斷這些錯誤是不是同個原因導致的,以及它們對使用者造成什麼影響,再決定要怎麼提示,應該能減少一次出現太多訊息的情況。
像這次的情境,畫面初始化時有 3 支 API 失敗,就可能一次出現 3 個錯誤提示。如果確認它們都是因為登入過期而失敗,是不是可以統一提示「登入過期,請重新登入」?如果原因不同,但都影響了初始化資料的載入,是不是也能依實際影響整合成一則提示呢?
又或是假設同時發生登入過期和其他資料載入失敗,以優先度來說,登入過期可能是使用者比較需要先知道的資訊。
如此一來,以工程面來說,我們需要先根據錯誤原因及操作情境分類,再判斷哪些提示可以整合,以及哪些資訊應該優先顯示。
再決定如何開發
後端可以在 HTTP Status 以外,回傳一個可分類的錯誤代碼。前端收到錯誤後,可以先依代碼辨識原因,再考慮它發生在哪個操作,以及對使用者造成什麼影響,才能決定怎麼顯示提示。
錯誤該怎麼分組?
知道錯誤原因和操作情境後,就能進一步判斷哪些提示適合放在一起。回到前面提到的畫面載入情境,我認為可以從兩種情況來思考:
- 相同原因:去除重複提示。 三支 API 都確認因登入過期失敗時,可以統一顯示「登入過期,請重新登入」。但收到 HTTP 401 時,仍要依認證流程判斷原因,不能直接認定登入過期。
- 不同原因、共同影響:彙整提示。 同一次初始化中,統計和通知資料因不同原因載入失敗,而訂單資料成功。如果知道這批請求的結果,可以考慮顯示「部分資料載入失敗」。
如果不知道錯誤是不是屬於同一次操作、造成什麼影響,就不一定能用同一則訊息說明。例如初始化失敗和使用者按下儲存後失敗,即使發生時間接近,也應該分開判斷。提示的內容也要符合實際情況:部分資料成功載入時,不應讓使用者以為整個畫面都無法使用。
錯誤的優先度
分組之外,還要決定使用者應該先知道什麼。像登入狀態失效會影響後續操作,可以比一般資料載入失敗更優先處理;使用者主動執行的儲存操作失敗,也需要保留明確回饋。
優先度要依錯誤對使用者的影響及操作情境決定,而不是只依 HTTP Status 排序。優先顯示某個錯誤,也不代表其他需要使用者知道的錯誤就可以被忽略。
前端可以怎麼處理?
假設 API 分散在不同 Component 呼叫,可以考慮用 Pinia 這類狀態管理工具收集錯誤與通知狀態,再根據錯誤原因、操作情境及已知影響分類,決定去重、彙整或分別顯示。各 Component 仍然負責自己的資料與畫面狀態;這些錯誤是否屬於同一次操作,以及實際造成什麼影響,也需要由相關流程提供足夠資訊判斷。
錯誤代碼可以對應到集中管理的使用者文案;未知代碼則提供一般提示,診斷資訊依專案規範另行記錄,避免直接顯示未經確認的後端錯誤訊息。
這裡還有一個取捨:等一批請求完成後再彙整,可以取得較完整的結果,但使用者也會等比較久。像確認登入失效這類需要盡快處理的情況,可以先交由認證流程處理;其他錯誤要等待多久、晚到的結果怎麼處理,則需要依操作情境決定。
參考資料
- OWASP:Handle all Errors and Exceptions:錯誤訊息與診斷資訊的適當揭露。
- TanStack Query:Global and local onError callbacks:集中處理錯誤,以及依額外資訊決定通知方式。
- Prometheus:Alertmanager:監控告警的分組與去重概念。
- Grafana:Group alert notifications:告警分組條件及通知等待時間的取捨。
- React-Toastify:Prevent duplicate:避免重複顯示 Toast 的機制。