錯誤處理和UX解釋
1)為什麼這很重要
錯誤不是「紅色文本」,而是腳本的延續。好的UX錯誤:- 解釋發生了什麼,接下來該怎麼做,
- 保存輸入的數據並防止丟失進度,
- 給出安全的重復或替代路徑,
- 保持可用狀態(SR/鍵盤),不透露額外內容。
2)錯誤類型(用於接口)
1.數據驗證(4xx client):空白/錯誤字段、格式、長度、規則沖突。
2.業務規則:限制,地理限制,KYC/KYB,雙打,不可用插槽。
3.權利/永久化:角色,獲得資源,年齡限制。
4.網絡/服務器:定時,離線,5xx,擁塞,利率限制。
5.沖突/狀態:409/412(數據更改),比賽,鎖定。
6.資源缺失:404/410,已刪除/已遷移。
7.支付和風險:銀行/PSP拒絕,反欺詐和責任遊戲限制。
3)頻道和顯示級別
在上下文中選擇「音量」:規則:不要把關鍵藏在烤面包/hover中。用戶觀看的地方,消息也在那裏。
4)文案撰寫錯誤
結構:原因→後果→行動。
語氣:誠實,中立,無過錯。
具體:指定字段/條件,避免代碼和堆棧。
按鈕操作:重復、更改地圖、重置過濾器、打開聊天。
敏感數據:不顯示(PAN掩碼,個人屬性)。
示例
好: "付款沒有通過:銀行拒絕了交易。嘗試另一種方法或稍後重復。"
不好: "錯誤500。 出事了
好吧: "白天支出的限制已經達到。設置新的限制或明天嘗試。"
好: "文件太大(最大25 MB)。吞噬或下載多個文件。"
5)行為和重點(A11y)
將錯誤輸出到焦點上下文中:將焦點轉移到第一個錯誤字段。
生活區域:"role="status""(polite)用於信息,'role="alert""(assertive)-用於關鍵。
可見的「:focus-visible」,≥ AA的對比,顏色替代品(圖標/文本)。
消息通過「aria-describedby」綁定到字段。
html
<label for = "pwd "> Password </label>
<input id="pwd" name="password" aria-describedby="pwd-err" aria-invalid="true">
<p id = "pwd-err" role = "alert"> Minimum 8 characters </p>
6)Retrai,backoff和idempority
如果有成功的機會(網絡故障,5xx,利率限制),則提供重播。
指數反向1-2-4-8 s,嘗試限制,可理解的「重復」按鈕。
關鍵交易(利率/付款):強制性Idempotency-Key →排除雙打。
回滾樂觀更新-清晰的視覺回報+解釋。
js async function retry(fn, attempts=3){
let wait=1000; for(let i=0; i<attempts; i++){
try{ return await fn(); }catch(e){ if(i===attempts-1) throw e; await new Promise(r=>setTimeout(r,wait)); wait=2; }
}
}
7)離線,定時和部分內容
離線:我們顯示「無連接」橫幅、腰果訪問(只讀)、同步隊列。
Taymauts:UI-taymaut(3-5 s)→「等待確認……」狀態,安全重播/取消。
部分成功:保持成功;標記「不同步」。
8)沖突與競爭
409/412:數據已過時。提供「更新」並顯示diff(發生了什麼變化)。
鎖定:通知誰持有設備,以及多長時間,「請求訪問」按鈕。
9) UI模板樣本
頁面橫幅:html
<div class="banner banner--error" role="alert">
<strong> Connection failed. </strong> Shows cached data.
<button class =" btn btn--ghost" id = "retry "> Retry </button>
</div>
關鍵錯誤調制解調器:
html
<div role="alertdialog" aria-labelledby="err-title" aria-describedby="err-desc">
<h2 id = "err-title "> Session expired </h2>
<p id = "err-desc "> Sign in again to continue. </p>
<button class = "btn "> Sign in </button>
<button class =" btn btn--ghost"> Home </button>
</div>
React ErrorBoundary(具有ID相關性):
tsx function Fallback({ id, onRetry }: { id: string; onRetry: ()=>void }) {
return (
<div role="alert" className="banner banner--error">
<strong> We couldn't load the page. </strong>
<div> Try again. Код: <code>{id}</code> <button onClick={()=>navigator. clipboard. writeText (id)}> Copy </button> </div>
<button onClick = {onRetry}> Retry </button>
</div>
);
}
10)錯誤令牌(設計系統)
json
{
"error": {
"tones": { "danger": "#", "warning": "#", "info": "#" },
"aria": { "polite": true, "assertive": true },
"timing": { "toastMs": 3500, "retryBackoffMs": [1000,2000,4000] },
"layout": { "fieldGap": 8, "bannerIcon": 20 }
}
}
CSS預設:
css
.banner--error { background: var(--bg-danger); color: var(--on-danger); padding: 12px 16px; border-radius: 12px; }
.field-error { color: var(--role-danger); margin-top: 6px; font-size:.875rem; }
11)安全和隱私
我們不會輸出堆棧路徑、內部ID、DB路徑。
我們掩蓋敏感值(地圖、文檔)。
消息不應提示攻擊者(例如,帳戶存在)。
要支持-ID相關性而不是零件。
json
{"level":"error","event":"payment_fail","correlation_id":"c-8f1...","user_id":"u-","route":"/pay","psp_code":"DO_NOT_EXPOSE_TO_USER"}
12)度量與控制
錯誤發生時的INP和長期任務份額(錯誤不應「掛起」UI)。
Retry success rate,錯誤1000操作,恢復前時間。
CTR在「幫助/聊天」上,被遺棄的表格百分比。
熱圖:現場錯誤最常見的地方。
13) QA支票清單
可用性
- 重點關註第一個錯誤的領域;「aria-describedby」/「aria-invalid」展出。
- 關鍵信息是'role='alert';AA ≥對比。
行為
- 表格數據不會因錯誤而丟失。
- 有一個可以理解的「Retry」和正確的背景。
- 離線模式/kesh工作;看到的橫幅。
文案撰寫
- 原因→行動;沒有技術術語和指控。
- 文本是本地化的,並且不會打破網格。
安全性
- 沒有PII/秘密泄漏;我們只顯示安全代碼/ID。
- 用於關鍵操作的冪等性。
14) iGaming的細節
投註:- UI立即記錄了「忙碌」;延遲時>3 c-「等待確認……」
- 失誤:誠實狀態(「市場關閉」,「系數改變」)+安全的「回歸」。
- 排除雙重出價的偶數鍵。
- 區分「銀行/PSP故障」與「服務器故障」。第一個是「選擇其他方法」,第二個是「Retry」。
- KYC/AML透明步驟;鏈接"為什麼需要?».
- 語氣有愛心,沒有壓力。「達到極限-暫停或更新極限。」
- 沒有耀斑/霓虹燈;AAA對比,SR可用性。
- 明確解釋限制,並提供「熟悉規則/支持」。
15)反模式
「出了問題」,沒有行動和背景。
錯誤後重置表格。
在敬酒中隱藏關鍵的3秒鐘。
只有沒有文本/圖標的顏色。
無休止的撤退,沒有取消的可能性。
顯示內部代碼/堆棧跟蹤。
16)設計系統中的文檔
Компоненты: `FieldError`, `FormError`, `PageBanner`, `AlertDialog`, `ErrorBoundary`.
音調/對比/時間令牌,a11 y預設和ARIA示例。
具有文本模板的典型腳本映射(驗證,網絡,權利,支付)。
「Do/Do n't」:帶有故障/成功度量的實際前後屏幕。
簡短摘要
讓錯誤易於理解和管理:以人性化的語言說話,保留輸入的數據,提供安全的重播和替代品,尊重可用性和隱私。然後,即使是不合時宜的情況也保持信任,並且不會中斷用戶的路徑-尤其是在關鍵的投註和支付情況下。