聽友人說 Error Code 錯誤碼設計 很簡單啊~這好像很基本,但為什麼會特別寫這篇呢?最近剛執行完一個專案,不得不說,當你遇到一個沒有經驗、又不聽勸的後端人員,讓前端串接時還要被迫開發「通靈技能」,除了 coding 到懷疑人生外,就只剩下想把手指下的 Enter、E、J、A、Shift、ESC 等鍵牢牢烙印在對方後腦杓的衝動了。
API Error Code(錯誤碼定義)是許多初學者在系統設計初期最常踩中的坑。良好的錯誤碼設計能大幅提升前後端串接與後期除錯效率;但若一開始隨意定義,到了 SIT 與 UAT 測試階段 或正式上線後,就會把整個團隊搞得烏煙瘴氣。
⚡ 快速跳轉(依實務情境選擇):
標準 API Error Code 回傳 JSON 範本(直接複製)
在看令人頭疼的反面教材之前,若你正在為新專案制定 API 錯誤回傳格式,建議直接採用「HTTP Status Code 標示協定層狀態 + error_code 標示唯一業務語意 + request_id 追蹤 Log」的標準結構(對齊 IETF RFC 9457 精神):
// HTTP/1.1 422 Unprocessable Content
// Content-Type: application/json; charset=utf-8
{
"success": false,
"error": {
"code": "USER_EMAIL_INVALID",
"numeric_code": 102002,
"message": "Email 格式不正確,請重新檢查",
"details": [
{
"field": "email",
"issue": "format_invalid",
"message": "必須包含 @ 與有效網域名稱"
}
],
"request_id": "req_9f8a7b6c5d4e"
}
}

為什麼需要這樣分層設計?因為網路上這類實務教學很少,許多初學者往往東看一個、西抄一個,再加上自身腦補來產出錯誤碼。當新手很有自信地交出 API 文件時,最常出現以下三種令人崩潰的定義方法:
- 大雜燴的流水編號法 – 新手天賦技能
- 一碼多解釋的通靈大法 – 被程式耽誤的通靈王
- 萬年 HTTP 200 OK 包裝錯誤 – 讓監控與攔截器全面失靈的假性成功
下面就一一來剖析個別的症狀與踩坑原因。
反模式一:大雜燴的流水編號法 – 新手天賦技能
先來說說什麼是『大雜燴的流水編號法』。這很簡單,依照流水號一路往下編,想到什麼編什麼,一去不回頭,甚至把「成功」跟「失敗」全部塞進同一張流水號表,如:
// ❌ 反例:無分類、成功與失敗混編的流水號對照表
const ERROR_CODE_MAP = {
"00001": "刪除成功",
"00002": "編輯失敗",
"00003": "登入成功",
"00004": "會員資料編輯成功",
"00005": "分類新增失敗",
"00006": "金流缺少資料"
// ......想到什麼就往後加 00007, 00008
};
這也是新手最常見的做法,缺點顯而易見:
- 毫無模組邏輯,無法從編號辨識來源:看到
00002或00005時,完全看不出這是「會員模組」、「商品分類」還是「金流模組」的錯誤。 - 成功與失敗混為一談:正常請求本來就應該透過 HTTP
200 OK/201 Created表達成功,不該把「刪除成功 (00001)」、「登入成功 (00003)」也當成 Error Code 混編。 - 後續維護與擴充災難:用在開發單人獨立的小工具倒還堪用;但放在一般專案、網站或 CMS 後台,當會員模組要新增第二種錯誤時,編號卻已經跳到
00089,大幅增加團隊 Debug 與查表時間。
如果你是初次嘗試……你還有救,多經歷幾個專案,將「模組前綴」與「錯誤類型」拆開,你會逐漸找到脈絡。
— 老人言
反模式二:一碼多解釋的通靈大法 – 被程式耽誤的通靈王
看懂以下的定義方式,可能需要點特殊體質;如果你也這樣定義……你要轉職嗎?
// ❌ 反例:一碼多義(102001 重複定義)與多碼同義(103050 / 487487 都是格式錯誤)
const PSYCHIC_ERROR_CODES = {
"001001": "失敗",
"102001": "Email 資料未填寫",
"102001": "資料格式錯誤", // 💥 撞碼:跟上一行共用 102001!
"103001": "資料未填寫",
"103050": "資料格式錯誤",
"103001": "Email 資料未填寫", // 💥 撞碼:103001 到底是什麼未填?
// ......
"487487": "資料格式錯誤" // 💥 隨心情亂跳號
};
在上面的定義中,你可以看到三個致命問題:
- 一碼多義(前端被迫通靈):同一組
102001被重複定義了多個解釋。假設前端串接 API 收到code: "102001",到底該在畫面上提示使用者「Email 未填寫」還是「資料格式錯誤」?尤其當網站需要支援多國語系(i18n)時,前端必須依賴唯一的error_code去對應語系字典,一碼多義會讓多語系映射直接崩潰。 - 多碼同義(規則失控):
102001、103050、487487全都代表「資料格式錯誤」,卻沒有統一的編碼規則,後期接手的工程師根本不敢動舊錯誤碼。 - 含糊不清的萬用錯誤(
001001: 失敗):回傳一個只有「失敗」兩個字的錯誤碼,不論對使用者提示或後端排查 Log 都毫無幫助。
如果你堅持這樣定義了……你要不要轉行,以免禍害他人。
— 老人言
反模式三:萬年 HTTP 200 OK 包裝錯誤 – 假性成功陷阱
除了上面兩種編號亂象,實務上還有第三種常見坑:後端不論發生參數驗證失敗、未登入、甚至資料庫連線崩潰,HTTP Status Code 永遠回傳 200 OK,只在 JSON 內文塞一個負數或錯誤字串:
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "error",
"code": "001001",
"message": "資料庫連線失敗"
}
這種「假性 200 OK」會帶來三個嚴重副作用:
- 前端 HTTP 攔截器失效:現代前端使用
fetch或Axios搭配各種 HTTP 請求方法(GET / POST / PUT / DELETE) 時,通常會在統一的 Error Interceptor 攔截401(自動刷新 Token 或導回登入頁)與5xx(跳出系統繁忙提示)。全部回傳200 OK會迫使前端在每個 API 呼叫處手寫if (res.data.code !== '00000')。 - CDN 與瀏覽器誤快取錯誤結果:若針對
GET請求配置了快取策略,CDN 看到HTTP 200 OK可能會把「資料庫連線失敗」的 JSON 當成正常資料快取起來,導致全站用戶持續看到錯誤。 - APM 監控與告警失明:Cloudflare、Nginx Log、Sentry 或 Datadog 等監控工具預設依據 HTTP
4xx/5xx比例計算 API 錯誤率(Error Rate)。萬年200 OK會讓系統崩潰時儀表板依然顯示「100% 綠燈正常」。
HTTP Status Code (400 / 422 / 500) 與業務 Error Code 怎麼分工?
要徹底避免上述三大反模式,核心原則只有一句話:「HTTP Status Code 負責協定層大分類,Business Error Code 負責唯一業務語意」。以下整理台灣工程師最常混淆的狀態碼分工對照表:
| HTTP 狀態碼 | 適用情境 | 範例業務 Error Code | 前端處理策略 |
|---|---|---|---|
400 Bad Request | JSON 語法解析失敗、型別錯誤或缺少必要 Query 參數 | REQ_INVALID_JSON (100001) | 檢查前端傳參格式與 Payload 型別 |
401 Unauthorized | 未帶 Token、Token 過期或簽章無效(尚未通過身分認證) | AUTH_TOKEN_EXPIRED (101001) | 觸發 Refresh Token 或導向登入頁 |
403 Forbidden | 已登入但角色權限不足、或帳號遭停權 | AUTH_PERMISSION_DENIED (101002) | 顯示無權限提示,不重試請求 |
404 Not Found | 請求的路由或目標資源 ID(如訂單、文章)不存在 | ORDER_NOT_FOUND (201001) | 導向 404 頁面或提示資源已移除 |
409 Conflict | 資源狀態衝突(如 Email 已註冊、庫存扣減版本衝突) | USER_EMAIL_DUPLICATED (102003) | 提示使用者更換帳號或重新整理狀態 |
422 Unprocessable | JSON 語法合法,但業務欄位驗證失敗(如密碼強度不足、Email 格式錯) | USER_EMAIL_INVALID (102002) | 依據 details[].field 標紅對應表單欄位 |
429 Too Many Requests | 觸發 API 速率限制(Rate Limiting)或簡訊發送冷卻中 | RATE_LIMIT_EXCEEDED (109001) | 讀取 Retry-After 標頭並禁用按鈕倒數 |
500 Internal Error | 後端未預期例外、資料庫異常(嚴禁對外裸露 SQL Stack Trace) | SYS_INTERNAL_ERROR (500001) | 顯示通用系統維護提示並附帶 request_id |
結論與下篇預告
Error Code 錯誤碼設計 乍看之下只是定義幾個數字或字串,但實際上直接決定了團隊日後的除錯成本與系統可維護性。總結本篇重點,在動手編碼前請務必守住三條底線:
- 禁止無分類的流水號混編:切勿將成功狀態與不同模組的錯誤塞進同一組流水號。
- 嚴守「一碼一義」鐵律:每個業務
error_code只能對應唯一一種錯誤原因,讓前端表單驗證與多語系字典能 100% 精準對應。 - 正確搭配 HTTP Status Code:善用
400、401、403、409、422、500表達協定層狀態,別再用萬年200 OK包裝錯誤。
至於在中大型專案或跨系統串接時,如何借鏡「產品編號(Source 來源模組 + Code 分類流水號)」設計出具備高擴充性與高可讀性的編碼規則? 請接著閱讀下一篇實務拆解:
匿名訪客
請問有下篇嗎 謝謝
米糕
有哦有哦~之前看到了你的留言,剛好1月專案比較多,已經寫好搂,希望對你有幫助。