签入版本
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
# 接口响应规范
|
||||
|
||||
:::tip 说明
|
||||
后端所有接口统一返回 `R.ok()` / `R.failed()` 格式的 JSON 响应,前端通过 `VAxios` 的 `transformRequestData` 拦截器统一解包处理。
|
||||
:::
|
||||
|
||||
## 响应格式
|
||||
|
||||
### 成功响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": { "id": 1, "name": "测试岗位", "status": 1 },
|
||||
"msg": "操作成功",
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
### 失败响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"data": null,
|
||||
"msg": "岗位名称不能重复",
|
||||
"ok": false
|
||||
}
|
||||
```
|
||||
|
||||
### 分页响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": [
|
||||
{ "id": 1, "name": "岗位1", "status": 1, "status_name": "正常" },
|
||||
{ "id": 2, "name": "岗位2", "status": 2, "status_name": "停用" }
|
||||
],
|
||||
"count": 100,
|
||||
"msg": "操作成功",
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
## 后端实现
|
||||
|
||||
位于 `src/core/response.py`:
|
||||
|
||||
```python
|
||||
from flask import jsonify
|
||||
|
||||
class R:
|
||||
@staticmethod
|
||||
def ok(data=None, msg="操作成功", **kwargs):
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"data": data,
|
||||
"msg": msg,
|
||||
"ok": True,
|
||||
**kwargs, # 支持额外字段,如 count
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def failed(msg="操作失败", data=None):
|
||||
return jsonify({
|
||||
"code": 1,
|
||||
"data": data,
|
||||
"msg": msg,
|
||||
"ok": False,
|
||||
})
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```python
|
||||
from src.core.response import R
|
||||
|
||||
# 成功
|
||||
return R.ok(data=user_info)
|
||||
return R.ok(data=list, count=total) # 分页
|
||||
return R.ok(msg="添加成功")
|
||||
|
||||
# 失败
|
||||
return R.failed(msg="用户名已存在")
|
||||
return R.failed("参数错误")
|
||||
```
|
||||
|
||||
## 前端拦截器
|
||||
|
||||
`VAxios` 的 `transformRequestData` 统一解包响应:
|
||||
|
||||
```typescript
|
||||
// src/utils/http/axios/index.ts
|
||||
transformRequestData: (res: AxiosResponse<Result>, options: RequestOptions) => {
|
||||
const { code, data, msg } = res.data;
|
||||
|
||||
// 业务成功(code === 0):直接返回 data
|
||||
if (code === ResultEnum.SUCCESS) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// 业务失败(code === 1):弹出错误提示
|
||||
if (code === ResultEnum.ERROR) {
|
||||
ElMessage.error(msg);
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
// 登录超时(code === 401):弹出确认框,跳转登录页
|
||||
if (code === ResultEnum.TIMEOUT) {
|
||||
ElMessageBox.confirm('登录身份已失效,请重新登录!', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
showCancelButton: false,
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
storage.clear();
|
||||
window.location.href = '/login';
|
||||
});
|
||||
throw new Error(msg);
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
解包后调用方拿到的是 `data` 字段内容:
|
||||
|
||||
```typescript
|
||||
// 普通接口:data 就是业务数据
|
||||
const result = await positionAdd(formData);
|
||||
// result = { id: 1, name: "测试岗位", ... }
|
||||
|
||||
// 分页接口:data 包含 list 和 count
|
||||
const result = await getPositionList(params);
|
||||
// result = { data: [...], count: 100, msg: "操作成功", ok: true, code: 0 }
|
||||
```
|
||||
|
||||
## 字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `code` | number | 业务码:0=成功,1=失败,401=登录超时 |
|
||||
| `data` | any | 业务数据 |
|
||||
| `count` | number | 分页总数(仅分页接口) |
|
||||
| `msg` | string | 提示消息 |
|
||||
| `ok` | boolean | 业务是否成功 |
|
||||
|
||||
## 错误码规范
|
||||
|
||||
| code | 说明 | 前端行为 |
|
||||
|------|------|----------|
|
||||
| 0 | 成功 | 返回 `data` |
|
||||
| 1 | 业务失败 | `ElMessage.error(msg)` + `throw` |
|
||||
| 401 | 未登录或 Token 过期 | 弹出确认框 → 跳转登录页 |
|
||||
|
||||
HTTP 状态码始终为 200,业务成功/失败通过 `code` 字段区分。
|
||||
|
||||
## 前端错误展示
|
||||
|
||||
业务错误通过 `ElMessage.error` 弹出提示,无需组件手动处理:
|
||||
|
||||
```typescript
|
||||
// 组件中直接调用,错误由拦截器处理
|
||||
try {
|
||||
await positionAdd(formData);
|
||||
message('操作成功');
|
||||
} catch (e) {
|
||||
// 拦截器已弹出 ElMessage.error,此处可选处理
|
||||
}
|
||||
```
|
||||
|
||||
:::tip 温馨提示
|
||||
HTTP 状态码始终为 200,业务成功/失败通过 `code` 字段区分。这避免了 HTTP 状态码与业务状态码的混淆。前端拦截器统一处理错误提示,业务代码只需处理成功逻辑。
|
||||
:::
|
||||
|
||||
## 总结
|
||||
|
||||
接口响应规范统一使用 `R.ok()`/`R.failed()` 格式,`code=0` 表示成功返回 `data`,`code=1` 表示失败弹出 `msg`,`code=401` 表示登录超时跳转登录页。前端 `VAxios` 的 `transformRequestData` 拦截器统一解包,调用方直接使用业务数据。
|
||||
Reference in New Issue
Block a user