docs: 新增前后端集成开发规范,更新项目规则与进度文档

- 创建 docs/conventions/frontend-backend-integration.md
  完整规范:API响应格式、HTTP状态码语义、前端错误处理、后端错误处理、
  前后端错误码对照表、安全约束、检查清单
- 更新 .cursor/rules/project-context.mdc 加入前后端联动规范6条
- 更新 CURRENT_STATUS.md 记录修复内容和规范引用

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-03-02 14:12:06 +08:00
parent e1348f57f2
commit cfb1651480
3 changed files with 273 additions and 5 deletions

View File

@@ -0,0 +1,204 @@
# 前后端集成开发规范
> **适用范围**EchoChat 项目全端Go 后端 + admin 管理端 + frontend 用户端)
> **创建日期**2026-03-02
> **最后更新**2026-03-02
---
## 一、API 响应格式规范
### 1.1 后端统一响应结构
所有后端 API 必须使用 `pkg/utils/response.go` 中的 `Response*` 系列函数返回响应,保证结构一致:
```json
{
"code": 0,
"message": "success",
"data": {},
"trace_id": "uuid-v4",
"time": "2026-03-02 14:00:00"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `code` | int | 业务状态码0=成功,非 0=HTTP 状态码 |
| `message` | string | 人类可读的描述信息,**前端直接展示给用户** |
| `data` | any | 业务数据,失败时为 null |
| `trace_id` | string | 请求追踪 ID用于日志排查 |
| `time` | string | 服务器响应时间 |
### 1.2 后端 Response 函数对照
| 函数 | HTTP Status | code | 使用场景 |
|------|-------------|------|----------|
| `ResponseOK` | 200 | 0 | 请求成功 |
| `ResponseCreated` | 201 | 0 | 资源创建成功 |
| `ResponseBadRequest` | 400 | 400 | 参数错误、业务规则校验失败 |
| `ResponseUnauthorized` | 401 | 401 | 认证失败密码错误、Token 无效/过期) |
| `ResponseForbidden` | 403 | 403 | 权限不足、账号被禁用 |
| `ResponseNotFound` | 404 | 404 | 资源不存在 |
| `ResponseError` | 500 | 500 | 服务器内部错误 |
### 1.3 message 字段要求
- **必须是中文**,面向最终用户
- **必须精准描述错误原因**,不能笼统(如 "操作失败"
- **安全场景除外**:登录时"用户不存在"和"密码错误"统一为 "账号或密码错误"
---
## 二、HTTP 状态码使用规范
### 2.1 状态码语义
| 状态码 | 语义 | 后端使用场景 |
|--------|------|-------------|
| 200 | OK | 查询成功、操作成功 |
| 201 | Created | 资源创建成功(注册、新建用户) |
| 400 | Bad Request | 参数校验失败、业务规则不满足 |
| 401 | Unauthorized | 认证失败密码错误、Token 过期/无效/已注销 |
| 403 | Forbidden | 权限不足:角色不匹配、账号被禁用/注销 |
| 404 | Not Found | 请求的资源不存在 |
| 500 | Internal Server Error | 服务器内部错误 |
### 2.2 安全约束
**登录接口的 401 响应**
```
✅ 正确:用户不存在 → 401 "账号或密码错误"
✅ 正确:密码错误 → 401 "账号或密码错误"
❌ 错误:用户不存在 → 404 "用户不存在"(暴露用户是否注册)
```
防止用户枚举攻击,登录场景下所有认证失败统一返回相同状态码和信息。
---
## 三、前端错误处理规范
### 3.1 核心原则
1. **后端 message 优先**:所有 HTTP 错误提示必须优先使用 `data.message`
2. **禁止硬编码覆盖**:不能用前端硬编码的文案替换后端返回的错误信息
3. **Fallback 仅兜底**`|| '默认文案'` 仅在后端无响应体或无 message 字段时触发
4. **按状态码分类处理**:不同 HTTP 状态码执行不同的副作用(跳转、清 Token 等)
### 3.2 管理端admin/)错误处理
文件:`admin/src/utils/request.js`
```
HTTP 响应成功2xx:
├─ code === 0 → 返回数据
└─ code !== 0 → ElMessage.error(data.message || '请求失败')
HTTP 响应错误:
├─ 401
│ ├─ 在登录页 → ElMessage.error(data.message || '登录已过期')
│ └─ 非登录页 → ElMessage.error(data.message || '登录已过期') + 清 Token + 跳转 /login
├─ 403 → ElMessage.error(data.message || '没有访问权限')
├─ 其他 → ElMessage.error(data.message || '请求错误(N)')
└─ 网络异常 → ElMessage.error('网络异常,请检查网络连接')
```
**401 场景区分的关键**:通过 `router.currentRoute.value.path === '/login'` 判断当前是否在登录页。登录页不清 Token 不跳转,仅显示错误。
### 3.3 前台用户端frontend/)错误处理
文件:`frontend/src/utils/request.js`
```
HTTP 响应成功2xx:
├─ code === 0 → resolve(data)
└─ code !== 0 → showToast(data.message || '请求失败')
HTTP 响应错误:
├─ 401
│ ├─ 登录/注册请求 → showToast(data.message || '登录已过期')
│ └─ 其他请求 → showToast(data.message || '登录已过期') + removeToken() + 跳转登录页
├─ 403 → showToast(data.message || '没有访问权限')
├─ 其他 → showToast(data.message || '请求错误(N)')
└─ 网络异常 → showToast('网络异常,请检查网络连接')
```
**401 场景区分的关键**:通过正则 `/\/auth\/(login|register)$/` 匹配请求 URL。登录/注册请求不清 Token 不跳转。
### 3.4 错误处理检查清单
新增 API 接口时,必须确认以下各项:
- [ ] 后端 Controller 使用正确的 `Response*` 函数
- [ ] 后端 Controller 的 error switch 覆盖所有已知业务错误
- [ ] 后端不使用 `_` 忽略 error至少 log warning
- [ ] 前端调用方的 catch 不自行覆盖 message交给拦截器统一处理
- [ ] 前端页面级 catch 只做状态清理(如 loading = false不重复弹提示
---
## 四、后端错误处理规范
### 4.1 Controller 层
- 使用 switch/case 或 if/else 匹配所有已知业务错误
- 每种错误映射到正确的 HTTP 状态码
- message 参数必须是用户友好的中文描述
- default 分支处理未知错误,返回 500
```go
if err := svc.DoSomething(ctx, req); err != nil {
switch err {
case service.ErrNotFound:
utils.ResponseNotFound(c, "资源不存在")
case service.ErrInvalidParam:
utils.ResponseBadRequest(c, "参数无效")
default:
logs.Error(ctx, funcName, "操作失败", zap.Error(err))
utils.ResponseError(c, "操作失败")
}
return
}
```
### 4.2 Service 层
- 定义明确的业务错误变量(`var ErrXxx = errors.New("...")`
- 不在 Service 层直接返回 HTTP 状态码,由 Controller 映射
- DAO 层的 `gorm.ErrRecordNotFound` 必须转换为业务错误
### 4.3 禁止忽略错误
```go
// ❌ 错误:忽略 error
roles, _ := s.roleDAO.GetUserRoleCodes(ctx, user.ID)
// ✅ 正确:处理 error
roles, err := s.roleDAO.GetUserRoleCodes(ctx, user.ID)
if err != nil {
logs.Warn(ctx, funcName, "获取角色失败", zap.Error(err))
roles = []string{}
}
```
---
## 五、前后端错误码对照表
| 后端场景 | HTTP | message 示例 | 前端行为 |
|---------|------|-------------|---------|
| 登录-密码错误 | 401 | 账号或密码错误 | 显示 message |
| 登录-用户不存在 | 401 | 账号或密码错误 | 显示 message |
| 登录-账号被禁用 | 403 | 账号已被禁用 | 显示 message |
| Token 过期 | 401 | 认证已过期或无效,请重新登录 | 显示 message + 清 Token + 跳转 |
| Token 已注销 | 401 | 认证已失效,请重新登录 | 显示 message + 清 Token + 跳转 |
| 缺少认证信息 | 401 | 缺少认证信息 | 显示 message + 清 Token + 跳转 |
| 权限不足 | 403 | 权限不足,需要角色: admin 或 super_admin | 显示 message |
| 参数校验失败 | 400 | 参数校验失败: ... | 显示 message |
| 用户名已注册 | 400 | 用户名或邮箱已被注册 | 显示 message |
| 不能禁用自己 | 400 | 不能禁用自己的账号 | 显示 message |
| 用户不存在 | 404 | 用户不存在 | 显示 message |
| 服务器内部错误 | 500 | 获取用户列表失败 | 显示 message |
| 网络异常 | - | (无响应体) | 显示前端 fallback 文案 |

View File

@@ -1,6 +1,6 @@
# EchoChat 项目开发进度
> **最后更新**2026-03-02Phase 1 全部完成 — Task 11 完成后更新
> **最后更新**2026-03-02前后端错误处理规范统一 + 安全加固
> **当前阶段**Phase 1 - 基础设施与用户认证
> **当前分支**`feature/phase1-foundation-and-auth`
> **实施计划**`docs/plans/2026-02-27-phase1-foundation-and-auth.md`
@@ -95,6 +95,8 @@ EchoChat/
└── docs/
├── api/ # API 接口文档
├── architecture/ # 系统架构文档
├── conventions/ # 开发规范文档
│ └── frontend-backend-integration.md # 前后端集成规范
├── plans/ # 实施计划文档
└── progress/ # 进度文档(本文件)
```
@@ -111,6 +113,7 @@ EchoChat/
6. **验证方式**Playwright MCP 进行页面自动化验证
7. **代码审查**:每个 Task 完成后,使用 `code-reviewer` 子代理进行结构化代码审查,对照实施计划和编码标准检查
8. **完成验证**:使用 `verification-before-completion` 技能,在声称完成前必须运行验证命令并确认输出结果
9. **前后端联动规范**:详见 `docs/conventions/frontend-backend-integration.md`,核心要求:前端错误提示必须优先使用后端 message禁止硬编码覆盖后端错误处理禁止忽略 error登录安全统一返回 401
---
@@ -157,10 +160,12 @@ cd frontend && npm run dev:h5
## 六、已知问题与注意事项
1. ~~前端工具模块使用了 CommonJS已修复为 ESM~~(已解决)
2. uni-app 的 `tabBar.custom: true` 配合自定义 TabBar 组件使用
3. 管理端和前台的 localStorage key 通过前缀隔离(`admin_` vs `echo_`
4. Go 依赖版本需匹配 Go 1.23.12,不要随意升级 Go 工具链
5. `.gitignore` 已配置忽略:`.cursor/``.vite/``node_modules/``dist/``*.png`(根目录截图)、`logs/`
2. ~~前端登录失败时错误提示不正确(硬编码"登录已过期"覆盖后端消息)~~(已修复,详见 `docs/conventions/frontend-backend-integration.md`
3. ~~后端登录时用户不存在返回 404 暴露用户是否注册~~(已修复为统一返回 401
4. uni-app 的 `tabBar.custom: true` 配合自定义 TabBar 组件使用
5. 管理端和前台的 localStorage key 通过前缀隔离(`admin_` vs `echo_`
6. Go 依赖版本需匹配 Go 1.23.12,不要随意升级 Go 工具链
7. `.gitignore` 已配置忽略:`.cursor/``.vite/``node_modules/``dist/``*.png`(根目录截图)、`logs/`
---