Skip to content

API 交互规范

本文档定义了 CondorAdmin 前后端的 API 交互规范,包括请求格式、响应格式、错误码、认证机制等。

基础约定

协议与编码

  • 协议:HTTP/HTTPS
  • 方法:GET(查询)、POST(创建/更新/删除)
  • 编码:UTF-8
  • Content-Typeapplication/jsonmultipart/form-data(文件上传)

Base URL

bash
# 开发环境
http://localhost:5566

# 生产环境
https://api.yourdomain.com

配置位置:

  • 前端:.env.test.env.prod 中的 VITE_SERVICE_BASE_URL
  • 后端:Webman 默认监听 0.0.0.0:8787

统一响应格式

成功响应

所有成功的 API 响应必须遵循以下格式:

json
{
  "code": "0000",
  "msg": "ok",
  "data": {
    // 业务数据
  }
}

字段说明

字段类型必填说明
codestring/int状态码,"0000"0 表示成功
msgstring提示信息(支持多语言)
dataany业务数据(可为 null、对象、数组)

失败响应

json
{
  "code": 4000,
  "msg": "参数错误",
  "data": []
}

分页响应

json
{
  "code": "0000",
  "msg": "ok",
  "data": {
    "total": 100,
    "list": [
      { "id": 1, "name": "张三" },
      { "id": 2, "name": "李四" }
    ]
  }
}

分页字段

字段类型说明
totalint总记录数
listarray当前页数据列表

错误码规范

标准错误码

错误码HTTP Status说明处理方式
0000200成功正常处理
401401未登录/Token 过期跳转登录页
403403权限不足显示提示,禁用操作
4000200业务错误显示错误提示
4001200参数错误显示错误提示
4002200数据不存在显示错误提示
4003200数据已存在显示错误提示
5000500服务器内部错误显示通用错误提示

后端错误码定义

后端使用 Backend 基类提供的方法返回统一格式:

php
// 成功
return $this->success('操作成功', ['id' => 1]);
// 等同于
return $this->json('0000', '操作成功', ['id' => 1]);

// 失败
return $this->fail('参数错误');
// 等同于
return $this->json(4000, '参数错误', []);

前端错误处理

typescript
// src/service/request.ts
instance.interceptors.response.use(
  (response) => {
    const { code, msg, data } = response.data;
    
    // 成功
    if (code === '0000' || code === 0) {
      return { data, error: null };
    }
    
    // Token 过期
    if (code === 401) {
      window.$message?.error(msg || '登录已过期,请重新登录');
      useAuthStore().resetStore();
      return { data: null, error: { code, msg } };
    }
    
    // 权限不足
    if (code === 403) {
      window.$message?.warning(msg || '权限不足');
      return { data: null, error: { code, msg } };
    }
    
    // 业务错误
    window.$message?.error(msg || '操作失败');
    return { data: null, error: { code, msg } };
  },
  (error) => {
    // 网络错误
    window.$message?.error('网络请求失败');
    return { data: null, error };
  }
);

认证机制

Token 认证

1. 获取 Token(登录)

请求

http
POST /api/condoradmin/account/login
Content-Type: application/json

{
  "username": "admin",
  "password": "MTIzNDU2", // RSA 加密后的 Base64
  "captcha": "abcd"
}

响应

json
{
  "code": "0000",
  "msg": "登录成功",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_in": 7200
  }
}

2. 使用 Token

前端在所有需要认证的请求中携带 Token:

http
GET /api/condoradmin/admin/index
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Accept-Language: zh-CN

请求头说明

Header必填说明
AuthorizationBearer <token> 格式
Accept-Language语言标识(zh-CN, en-US)

3. Token 验证流程

前端发送请求(带 Token)

后端 AuthToken 中间件

1. 解析 Authorization Header

2. 从 Redis 查询 Token:admin:token:{token}

3. 判断 Token 是否有效
        ├─ 有效 → 继续执行
        └─ 无效/过期 → 返回 401

密码加密

前端 RSA 加密

typescript
import JSEncrypt from 'jsencrypt';

// 1. 获取公钥
const { data } = await fetchGetPublicKey();

// 2. 加密密码
const jse = new JSEncrypt();
jse.setPublicKey(data.publicKey);
const encryptedPassword = jse.encrypt(password);

// 3. 提交登录
await fetchLogin({
  username,
  password: encryptedPassword, // Base64 字符串
  captcha
});

后端 RSA 解密

php
// 1. 读取私钥
$privateKey = config('plugin.condoradmin.condor.rsa_private_key');

// 2. 解密密码
openssl_private_decrypt(
    base64_decode($encryptedPassword),
    $decrypted,
    $privateKey
);

// 3. 验证密码
password_verify($decrypted, $user->password);

请求规范

GET 请求(查询)

列表查询

http
GET /api/condoradmin/admin/index?page=1&limit=20&username=admin&status=1

通用参数

参数类型必填说明
pageint页码(默认 1)
limitint每页数量(默认 10,最大 500)
orderBystring排序字段(默认主键)
orderstring排序方式(asc/desc,默认 desc)

搜索参数(由 $searchable 定义):

php
protected array $searchable = [
    'username' => ['type' => 'string'], // 精确匹配
    'nickname' => ['type' => 'string'], // 精确匹配
    'status' => ['type' => 'int'],      // 精确匹配
    'created_at' => ['type' => 'timestamp'], // 时间范围
];

高级搜索

http
# LIKE 模糊查询
GET /api/admin/index?username=LIKE,admin

# IN 查询
GET /api/admin/index?status=IN,[1,2]

# BETWEEN 查询(时间戳)
GET /api/admin/index?created_at=[1640995200,1643673599]

# BETWEEN 查询(日期)
GET /api/admin/index?created_at=[2022-01-01,2022-01-31]

Selectpage(下拉选择)

http
GET /api/condoradmin/admin/selectpage?nickname=admin&id=1,2,3

响应

json
{
  "code": "0000",
  "msg": "ok",
  "data": {
    "total": 10,
    "list": [
      { "id": 1, "nickname": "管理员" },
      { "id": 2, "nickname": "运营" }
    ]
  }
}

POST 请求(操作)

添加

http
POST /api/condoradmin/admin/add
Content-Type: application/json

{
  "username": "zhangsan",
  "nickname": "张三",
  "password": "123456",
  "status": 1,
  "role_ids": [1, 2]
}

响应

json
{
  "code": "0000",
  "msg": "添加成功",
  "data": {
    "id": 10
  }
}

编辑

http
POST /api/condoradmin/admin/edit
Content-Type: application/json

{
  "id": 10,
  "nickname": "张三三",
  "status": 1
}

删除

http
POST /api/condoradmin/admin/del
Content-Type: application/json

{
  "ids": [10, 11, 12]
}

或单个删除:

http
POST /api/condoradmin/admin/del
Content-Type: application/json

{
  "id": 10
}

批量操作

http
POST /api/condoradmin/admin/multi
Content-Type: application/json

{
  "ids": [10, 11, 12],
  "field": "status",
  "value": 1
}

或批量更新多个字段:

http
POST /api/condoradmin/admin/multi
Content-Type: application/json

{
  "ids": [10, 11, 12],
  "values": {
    "status": 1,
    "group_id": 2
  }
}

文件上传

http
POST /api/condoradmin/attachment/upload
Content-Type: multipart/form-data

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="image.jpg"
Content-Type: image/jpeg

<binary data>
------WebKitFormBoundary
Content-Disposition: form-data; name="type_id"

1
------WebKitFormBoundary--

响应

json
{
  "code": "0000",
  "msg": "上传成功",
  "data": {
    "id": 123,
    "url": "/uploads/2024/01/01/abc123.jpg",
    "full_url": "https://cdn.example.com/uploads/2024/01/01/abc123.jpg",
    "filename": "image.jpg",
    "filesize": 102400,
    "storage": "local"
  }
}

多语言支持

前端请求头

http
Accept-Language: zh-CN

支持的语言:

  • zh-CN:简体中文
  • en-US:英文

后端响应

后端自动根据 Accept-Language 返回对应语言的提示信息:

php
// 使用 trans() 函数
return $this->fail(trans('condoradmin.parameter.can.not.be.empty'));

对应翻译文件:

  • plugin/condoradmin/app/i18n/zh-cn.php
  • plugin/condoradmin/app/i18n/en.php

数据验证

后端验证

使用 Respect\Validation 库:

php
// Model 中定义验证规则
public static function rules(): array
{
    return [
        'username' => Validator::stringType()->length(3, 20),
        'email' => Validator::email(),
        'status' => Validator::intVal()->between(0, 1),
    ];
}

// Controller 中自动验证
protected $modelValidate = true; // 启用模型验证

验证失败响应

json
{
  "code": 4001,
  "msg": "username must have a length between 3 and 20",
  "data": []
}

前端验证

使用 Naive UI 表单验证:

typescript
const rules = {
  username: [
    { required: true, message: '请输入用户名' },
    { min: 3, max: 20, message: '用户名长度为 3-20 个字符' }
  ],
  email: [
    { required: true, message: '请输入邮箱' },
    { type: 'email', message: '邮箱格式不正确' }
  ]
};

常见场景

场景1:获取列表数据

typescript
// 前端
const { data, error } = await fetchAdminList({
  page: 1,
  limit: 20,
  username: 'admin',
  status: 1
});

if (!error) {
  tableData.value = data.list;
  total.value = data.total;
}
php
// 后端(Backend 基类已实现)
public function index(Request $request)
{
    // 自动处理分页、搜索、排序
    // 自动应用数据权限
}

场景2:提交表单

typescript
// 前端
const handleSubmit = async () => {
  const { error } = await fetchAdminAdd({
    username: form.username,
    nickname: form.nickname,
    password: form.password
  });
  
  if (!error) {
    window.$message?.success('添加成功');
    router.back();
  }
};
php
// 后端(Backend 基类已实现)
public function add(Request $request)
{
    // 自动验证参数
    // 自动填充 dataLimitField
    // 自动事务处理
}

场景3:权限控制

typescript
// 前端
import { useAuthStore } from '@/store';

const authStore = useAuthStore();

// 检查权限
if (authStore.hasPermission('admin:add')) {
  // 显示添加按钮
}
php
// 后端(AuthPermission 中间件自动处理)
protected $noNeedLogin = ['login']; // 无需登录
protected $noNeedRight = ['profile']; // 无需权限(但需登录)

调试工具

开发环境

  • 后端调试模式:.env 中设置 APP_DEBUG=true
  • 前端网络面板:Chrome DevTools → Network
  • API 文档工具:Postman/Apifox

日志查看

bash
# 后端日志
tail -f runtime/logs/webman.log

# 前端控制台
console.log(response)

最佳实践

  1. 统一错误处理:使用响应拦截器统一处理错误
  2. Loading 状态:API 调用时显示 Loading
  3. 防抖节流:搜索、滚动等高频操作使用防抖/节流
  4. 请求取消:路由切换时取消未完成的请求
  5. 错误重试:网络错误时自动重试(限次数)
  6. 参数校验:前后端双重校验,前端优化体验,后端保证安全

相关文档