签入版本
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
# 接口响应规范
|
||||
|
||||
<!-- Copyright (c) 2021-2026 小蚂蚁云团队 版权所有 -->
|
||||
|
||||
:::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": {
|
||||
"records": [
|
||||
{ "id": 1, "name": "案例1", "status": 1 },
|
||||
{ "id": 2, "name": "案例2", "status": 2 }
|
||||
],
|
||||
"total": 100,
|
||||
"size": 10,
|
||||
"current": 1,
|
||||
"pages": 10
|
||||
},
|
||||
"msg": "操作成功",
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
## 后端实现
|
||||
|
||||
位于 `utils/R.py`:
|
||||
|
||||
```python
|
||||
from django.http import JsonResponse
|
||||
|
||||
def ok(data=None, msg="操作成功", code=0, **kwargs):
|
||||
response_body = {"code": code, "data": data, "msg": msg, "ok": True}
|
||||
if kwargs:
|
||||
response_body.update(kwargs)
|
||||
return JsonResponse(data=response_body)
|
||||
|
||||
def failed(msg="操作失败", code=1, data=None, **kwargs):
|
||||
response_body = {"code": code, "data": data, "msg": msg, "ok": False}
|
||||
if kwargs:
|
||||
response_body.update(kwargs)
|
||||
return JsonResponse(data=response_body)
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```python
|
||||
# 成功
|
||||
return R.ok(data=user_info)
|
||||
return R.ok(data=page_data) # 分页
|
||||
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 exampleAdd(formData);
|
||||
// result = undefined (add 接口无返回数据)
|
||||
|
||||
// 分页接口:data 包含 records、total 等
|
||||
const result = await getExamplePage(params);
|
||||
// result = { records: [...], total: 100, size: 10, current: 1, pages: 10 }
|
||||
```
|
||||
|
||||
## 字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `code` | number | 业务码:0=成功,1=失败,401=登录超时 |
|
||||
| `data` | any | 业务数据 |
|
||||
| `total` | 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