51 lines
3.5 KiB
Markdown
51 lines
3.5 KiB
Markdown
|
|
---
|
|||
|
|
kind: error_handling
|
|||
|
|
name: 前后端统一错误码与响应封装
|
|||
|
|
category: error_handling
|
|||
|
|
scope:
|
|||
|
|
- '**'
|
|||
|
|
source_files:
|
|||
|
|
- backend/src/utils/response.js
|
|||
|
|
- backend/src/middleware/auth.js
|
|||
|
|
- backend/src/app.js
|
|||
|
|
- frontend/src/service/request/index.ts
|
|||
|
|
- frontend/src/service/request/shared.ts
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 后端(Node.js + Express)
|
|||
|
|
|
|||
|
|
- **统一响应体**:`backend/src/utils/response.js` 导出 `ApiResponse`,提供 `success(data, msg)`、`error(msg, code=0)`、`noData(msg)` 三个工厂方法,所有业务路由通过 `res.json(ApiResponse.xxx(...))` 返回 `{ code, msg, data }` 结构。
|
|||
|
|
- **认证错误**:`backend/src/middleware/auth.js` 的 `authMiddleware` 对未登录/无效/过期 JWT 直接以 HTTP 401 + `{ detail: '...' }` 形式返回;`requireSuperAdmin` 对权限不足返回 403。这些 401/403 走的是 HTTP 状态码路径,不走 ApiResponse。
|
|||
|
|
- **异常捕获**:各路由文件内大量使用 `try/catch` 包裹异步逻辑,失败时调用 `ApiResponse.error(...)`;入口 `app.js` 仅在启动阶段同步数据库时 catch 并记录日志,未注册全局 `express` error handler,因此未捕获的异常会以 Node 默认方式抛出。
|
|||
|
|
- **无全局错误中间件**:未发现类似 `app.use((err, req, res, next) => ...)` 的全局错误处理中间件,错误传播依赖每个路由自行 try/catch 后返回 ApiResponse。
|
|||
|
|
|
|||
|
|
## 前端(Vue3 + Axios)
|
|||
|
|
|
|||
|
|
- **请求封装**:`frontend/src/service/request/index.ts` 基于 `@sa/axios` 的 `createFlatRequest` 创建 `request` 实例,集中处理成功/失败分支。
|
|||
|
|
- **成功判定**:`isDashboardSuccessCode` 将后端 `code === '1'` 或 `'2'` 视为成功(2 表示“无数据但仍 OK”),其余进入 `onBackendFail`。
|
|||
|
|
- **后端失败处理**:
|
|||
|
|
- 根据环境变量 `VITE_SERVICE_LOGOUT_CODES` / `VITE_SERVICE_MODAL_LOGOUT_CODES` / `VITE_SERVICE_EXPIRED_TOKEN_CODES` 分别执行静默登出、弹窗确认登出、刷新 token 并重试。
|
|||
|
|
- 通过 `showErrorMsg`(定义于 `shared.ts`)统一弹出错误提示,支持 `skipErrorToast` 配置由调用方抑制 toast。
|
|||
|
|
- **HTTP 错误处理**:`onError` 中针对 401 自动清理 auth store 并显示 detail;403 显示“无权限执行此操作”;其他错误优先取 `response.data.msg`,否则回退到 axios message。
|
|||
|
|
- **demo 请求**:`demoRequest` 使用独立的 success/fail 策略,不干扰主请求的错误流。
|
|||
|
|
|
|||
|
|
## 约定与规则
|
|||
|
|
|
|||
|
|
| 层面 | 约定 |
|
|||
|
|
|------|------|
|
|||
|
|
| 后端成功 | `ApiResponse.success(data, msg)` → `{ code: 1, msg, data }` |
|
|||
|
|
| 后端业务错误 | `ApiResponse.error(msg, code)` → `{ code, msg, data: null }`,code 为数字字符串(如 0) |
|
|||
|
|
| 后端空数据 | `ApiResponse.noData(msg)` → `{ code: 2, msg, data: null }`,前端视作成功 |
|
|||
|
|
| 认证失败 | 401 + `{ detail: '...' }`(JWT 相关) |
|
|||
|
|
| 权限不足 | 403 + `{ detail: '...' }` |
|
|||
|
|
| 前端成功判定 | `code === '1' || code === '2'` |
|
|||
|
|
| 前端错误展示 | 统一经 `showErrorMsg`,可通过 `config.skipErrorToast = true` 抑制 |
|
|||
|
|
| 全局错误中间件 | 后端未实现,需在各路由 try/catch 后返回 ApiResponse |
|
|||
|
|
|
|||
|
|
## 关键文件
|
|||
|
|
|
|||
|
|
- `backend/src/utils/response.js` — 统一响应体工厂
|
|||
|
|
- `backend/src/middleware/auth.js` — 认证/鉴权错误(401/403)
|
|||
|
|
- `backend/src/app.js` — 应用入口(仅启动期 try/catch)
|
|||
|
|
- `frontend/src/service/request/index.ts` — Axios 拦截器与错误分发
|
|||
|
|
- `frontend/src/service/request/shared.ts` — `showErrorMsg` 等共享工具
|