Skip to content

8.1 统一响应格式 ​

概述

所有接口返回统一的 JSON 结构,前端可据此判断请求结果。响应由 response\Result 类构造,保证全系统格式一致。

响应结构 ​

typescript
interface ApiResponse {
    code: number;   // 状态码:0=成功,其他=失败
    ok: boolean;    // 是否成功
    msg: string;    // 提示信息
    data: any;      // 响应数据
}

状态码定义 ​

code含义ok说明
0成功true业务成功
1业务失败false通用业务错误(参数错误、业务校验失败等)
401未授权falseToken 缺失/无效/过期
403禁止访问false权限不足
404数据不存在false查询的记录不存在
422参数验证失败falseValidate 校验不通过

成功响应 ​

普通成功 ​

json
{
    "code": 0,
    "ok": true,
    "msg": "操作成功",
    "data": {
        "id": 1,
        "username": "admin",
        "realname": "管理员",
        "createTime": "2026-01-01 00:00:00"
    }
}

带自定义消息 ​

json
{
    "code": 0,
    "ok": true,
    "msg": "添加成功",
    "data": { "id": 42 }
}

data 为 null ​

json
{
    "code": 0,
    "ok": true,
    "msg": "修改成功",
    "data": null
}

data 为数组 ​

json
{
    "code": 0,
    "ok": true,
    "msg": "操作成功",
    "data": [
        { "id": 1, "name": "选项一" },
        { "id": 2, "name": "选项二" }
    ]
}

分页响应 ​

json
{
    "code": 0,
    "ok": true,
    "msg": "操作成功",
    "data": {
        "records": [
            { "id": 1, "username": "admin", "createTime": "2026-01-01 00:00:00" },
            { "id": 2, "username": "user1", "createTime": "2026-01-02 00:00:00" }
        ],
        "total": 100,
        "size": 20,
        "current": 1,
        "pages": 5
    }
}

分页参数 ​

字段类型说明
recordsarray当前页数据列表
totalnumber总记录数
sizenumber每页条数
currentnumber当前页码
pagesnumber总页数(ceil(total / size))

失败响应 ​

通用业务失败 ​

json
{
    "code": 1,
    "ok": false,
    "msg": "用户名已存在",
    "data": null
}

参数验证失败 ​

json
{
    "code": 1,
    "ok": false,
    "msg": "参数验证失败",
    "data": "用户名不能为空"
}

批量验证失败 ​

json
{
    "code": 1,
    "ok": false,
    "msg": "参数验证失败",
    "data": [
        "用户名不能为空",
        "姓名不能为空"
    ]
}

数据不存在 ​

json
{
    "code": 1,
    "ok": false,
    "msg": "数据不存在",
    "data": null
}

未授权(Token 问题) ​

json
{
    "code": 401,
    "ok": false,
    "msg": "token已过期",
    "data": null
}

权限不足 ​

json
{
    "code": 403,
    "ok": false,
    "msg": "无访问权限",
    "data": null
}

字段说明 ​

字段类型说明
codenumber状态码,0=成功
okboolean是否成功
msgstring提示信息
dataany响应数据,失败时通常为 null 或错误详情

分页字段 ​

字段类型说明
data.recordsarray分页数据列表
data.totalnumber总记录数
data.sizenumber每页条数
data.currentnumber当前页码
data.pagesnumber总页数

后端 Result 类 ​

文件: extend/response/Result.php

方法清单 ​

方法说明codeok
success($data, $msg)成功响应0true
page($records, $total, $current, $size)分页响应0true
fail($msg, $code, $data)失败响应1false
unauthorized($msg)未授权401false
forbidden($msg)禁止访问403false
notFound($msg)数据不存在404false
validateError($errors)验证失败422false

使用示例 ​

php
// Controller 中通过 BaseController 调用
$this->success($data, '操作成功');
$this->success(['id' => $id], '添加成功');
$this->fail('用户名已存在');
$this->fail('缺少id参数', 1);

// 直接调用 Result 类
\response\Result::success($data);
\response\Result::fail('错误信息');
\response\Result::unauthorized('未授权');
\response\Result::forbidden('无权限');
\response\Result::notFound('数据不存在');
\response\Result::validateError('用户名不能为空');

驼峰自动转换 ​

响应数据自动从 snake_case 转为 camelCase:

数据库字段响应字段
create_timecreateTime
user_nameuserName
is_deleteisDelete
dept_iddeptId

可通过 config/api.php 的 camel_snake_convert 配置关闭。

前端响应处理 ​

Axios 响应拦截器 ​

typescript
// src/utils/http/axios/index.ts

axios.interceptors.response.use(
    response => {
        const { code, data, msg } = response.data;

        // 成功
        if (code === 0) {
            return data;
        }

        // Token 过期
        if (code === 401) {
            localStorage.clear();
            router.push('/login');
            return Promise.reject(new Error(msg));
        }

        // 权限不足
        if (code === 403) {
            ElMessage.error(msg || '无访问权限');
            return Promise.reject(new Error(msg));
        }

        // 其他业务错误
        ElMessage.error(msg || '操作失败');
        return Promise.reject(new Error(msg));
    },
    error => {
        ElMessage.error('网络错误');
        return Promise.reject(error);
    }
);

处理分页数据 ​

typescript
const fetchData = async () => {
    const res = await getUserPage({ pageNo: 1, pageSize: 20 });
    // res 已经是 data 部分(拦截器已解包)
    tableData.value = res.records;
    total.value = res.total;
};

处理导入结果 ​

typescript
const handleImport = async (file) => {
    const res = await importUsers(file);
    // res = { count: 8, errors: [{ row: 3, reason: "..." }] }
    if (res.errors.length === 0) {
        ElMessage.success(`成功导入 ${res.count} 条`);
    } else {
        ElMessage.warning(`成功 ${res.count} 条,失败 ${res.errors.length} 条`);
    }
};

常见响应场景汇总 ​

场景codemsgdata
查询成功0操作成功数据对象/数组
分页成功0操作成功{records, total, size, current, pages}
新增成功0添加成功{id: 42}
修改成功0修改成功null
删除成功0删除成功null
业务失败1具体错误信息null
参数验证失败1参数验证失败错误字符串或数组
Token 过期401token已过期null
无权限403无访问权限null
数据不存在404数据不存在null

小蚂蚁云团队 · 提供技术支持