从零到一:Ant Design Pro RESTful接口设计实战指南

从零到一:Ant Design Pro RESTful接口设计实战指南

【免费下载链接】ant-design-pro 👨🏻‍💻👩🏻‍💻 Use Ant Design like a Pro! 【免费下载链接】ant-design-pro 项目地址: https://gitcode.com/gh_mirrors/an/ant-design-pro

引言:你还在为前后端对接焦头烂额?

在现代Web应用开发中,前后端分离架构(Frontend-Backend Separation Architecture)已成为主流。然而,接口设计不当导致的对接效率低下、数据格式混乱、错误处理繁琐等问题,仍然困扰着许多开发团队。根据Stack Overflow 2024年开发者调查,37%的项目延期源于接口设计缺陷。

本文将以Ant Design Pro(以下简称"Pro项目")为基础,通过12个实战模块,系统讲解RESTful API设计规范与最佳实践。读完本文,你将能够:

✅ 掌握RESTful接口设计的核心原则与规范
✅ 理解Pro项目中API请求的实现机制
✅ 设计标准化的请求/响应数据结构
✅ 实现完善的错误处理与状态码管理
✅ 构建可扩展的API服务架构

一、RESTful API核心概念与Pro项目实践

1.1 RESTful API定义与原则

REST(Representational State Transfer,表述性状态转移)是一种软件架构风格,其核心原则包括:

  • 资源(Resource):使用URI(Uniform Resource Identifier,统一资源标识符)标识资源
  • 表现层(Representation):资源的表现形式(如JSON、XML)
  • 状态转移(State Transfer):通过HTTP方法实现资源状态的改变

Pro项目完全遵循RESTful规范,通过src/services/目录集中管理API请求。以下是Pro项目中典型的RESTful API实现:

// src/services/ant-design-pro/api.ts
/** 获取规则列表 GET /api/rule */
export async function rule(
  params: {
    current?: number;  // 当前页码
    pageSize?: number; // 页面容量
  },
  options?: { [key: string]: any },
) {
  return request<API.RuleList>('/api/rule', {
    method: 'GET',
    params: { ...params },
    ...(options || {}),
  });
}

1.2 HTTP方法与CRUD操作映射

RESTful API通过HTTP方法表达对资源的操作意图,Pro项目严格遵循这一规范:

HTTP方法操作类型Pro项目实现示例接口
GET查询资源rule()获取规则列表
POST创建资源addRule()新建规则
PUT更新资源updateRule()更新规则
DELETE删除资源removeRule()删除规则

⚠️ 注意:Pro项目中updateRuleremoveRule方法目前使用POST模拟PUT和DELETE,实际生产环境应使用标准HTTP方法以符合REST规范。

1.3 资源命名规范

Pro项目采用以下资源命名约定:

  • 使用名词复数形式表示资源集合(如/api/rules而非/api/ruleList
  • 使用嵌套URL表示资源间关系(如/api/users/{id}/orders
  • 使用查询参数进行过滤、排序和分页
// 正确:使用复数名词表示资源集合
GET /api/rules  

// 正确:使用嵌套URL表示资源关系
GET /api/users/123/orders  

// 正确:使用查询参数过滤
GET /api/rules?status=active&page=1&pageSize=10

二、Pro项目API请求架构深度解析

2.1 请求封装层次结构

Pro项目采用三层架构封装API请求,确保代码的可维护性和可扩展性:

mermaid

  1. 页面组件层:如pages/table-list/index.tsx,调用API服务层方法
  2. API服务层:如services/ant-design-pro/api.ts,定义接口方法
  3. 请求工具层:基于Umi Request封装,处理拦截、转换等

2.2 TypeScript类型定义

Pro项目通过TypeScript接口严格定义请求参数和响应数据结构,提供类型安全保障:

// src/services/ant-design-pro/typings.d.ts
declare namespace API {
  // 请求参数类型
  type LoginParams = {
    username?: string;
    password?: string;
    autoLogin?: boolean;
    type?: string;
  };
  
  // 响应数据类型
  type RuleList = {
    data?: RuleListItem[];
    total?: number;       // 列表总数
    success?: boolean;    // 请求是否成功
  };
  
  // 列表项类型
  type RuleListItem = {
    key?: number;
    name?: string;
    desc?: string;
    status?: number;
    updatedAt?: string;
    progress?: number;
  };
}

类型定义带来的优势:

  • 开发阶段的类型检查,减少运行时错误
  • IDE自动提示,提高开发效率
  • 接口文档与代码的一致性

2.3 请求配置与拦截器

Pro项目使用Umi Request作为请求库,支持请求/响应拦截、错误处理等高级功能:

// src/app.tsx 中配置请求拦截器
export const request = {
  interceptors: {
    request: {
      // 请求拦截器
      async handler(config) {
        // 添加认证令牌
        const token = localStorage.getItem('token');
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
    },
    response: {
      // 响应拦截器
      async handler(response) {
        // 统一处理错误
        if (response.data.success === false) {
          message.error(response.data.errorMessage || '操作失败');
        }
        return response;
      },
    },
  },
};

三、请求设计最佳实践

3.1 统一请求参数规范

Pro项目中请求参数遵循以下规范:

  1. 查询参数:用于GET请求的过滤、排序和分页

    // 分页查询示例
    rule({ current: 1, pageSize: 10 });
    
  2. 请求体:用于POST/PUT请求的复杂数据

    // 登录请求示例
    login({ username: 'admin', password: '123456' });
    
  3. 路径参数:用于标识特定资源

    // 获取单个用户信息(Pro项目建议实现)
    export async function getUser(id: number) {
      return request<API.User>(`/api/users/${id}`, { method: 'GET' });
    }
    

3.2 分页请求标准化设计

Pro项目采用行业标准的分页参数设计:

// 分页参数接口定义
type PageParams = {
  current?: number;  // 当前页码,从1开始
  pageSize?: number; // 每页条数
};

// 分页响应接口定义
type PageResponse<T> = {
  data: T[];         // 数据列表
  total: number;     // 总记录数
  current: number;   // 当前页码
  pageSize: number;  // 每页条数
  success: boolean;  // 请求状态
};

实现分页请求的最佳实践:

// 推荐的分页请求实现
export async function getUsers(
  params: PageParams & { keyword?: string; status?: number }
) {
  return request<PageResponse<API.User>>('/api/users', {
    method: 'GET',
    params: { ...params },
  });
}

3.3 高级查询设计

对于复杂查询需求,Pro项目推荐以下实现方式:

// 高级查询示例(Pro项目建议实现)
export async function searchProducts(
  params: {
    // 基础分页参数
    current?: number;
    pageSize?: number;
    // 高级查询参数
    keywords?: string;
    priceRange?: [number, number];
    categories?: number[];
    sortBy?: string;
    sortOrder?: 'asc' | 'desc';
    // 时间范围
    createdAt?: [string, string];
  }
) {
  return request<PageResponse<API.Product>>('/api/products/search', {
    method: 'GET',
    params: { ...params },
  });
}

四、响应数据结构设计规范

4.1 统一响应格式

Pro项目定义了统一的API响应格式,确保前端能够一致地处理返回数据:

// 成功响应格式
{
  "success": true,
  "data": { ... },      // 业务数据
  "message": "操作成功"  // 提示信息
}

// 错误响应格式
{
  "success": false,
  "errorCode": "E001",  // 错误码
  "errorMessage": "用户名或密码错误"  // 错误信息
}

在TypeScript中定义统一响应类型:

// 统一响应类型定义(Pro项目建议实现)
type ApiResponse<T = any> = {
  success: boolean;
  data?: T;
  errorCode?: string;
  errorMessage?: string;
  [key: string]: any;
};

// 使用示例
export async function getUser(id: number) {
  return request<ApiResponse<API.User>>(`/api/users/${id}`, { method: 'GET' });
}

4.2 数据类型规范

Pro项目中API响应数据类型遵循以下规范:

数据类型TypeScript类型示例值注意事项
字符串string"2024-09-01"日期使用ISO 8601格式
数字number123.45不使用NaN或Infinity
布尔值booleantrue不使用0/1代替
数组T[][1, 2, 3]空数组表示无数据
对象object{name: "foo"}空对象表示无数据
日期string"2024-09-01T12:00:00Z"使用UTC时间

4.3 状态码设计

Pro项目采用双重状态码机制:

  1. HTTP状态码:表示请求传输层面的状态
  2. 业务错误码:表示应用逻辑层面的状态

业务错误码设计规范:

// src/services/ant-design-pro/typings.d.ts
type ErrorResponse = {
  errorCode: string;    // 业务错误码
  errorMessage?: string;// 错误信息
  success?: boolean;    // 请求是否成功
};

推荐的业务错误码体系:

错误码前缀含义示例
E00x认证错误E001: 未登录, E002: 会话过期
E10x参数错误E101: 缺少参数, E102: 参数格式错误
E20x业务错误E201: 资源不存在, E202: 权限不足
E50x服务器错误E501: 数据库错误, E502: 第三方服务异常

五、错误处理机制

5.1 全局错误处理配置

Pro项目通过requestErrorConfig.ts配置全局错误处理策略:

// src/requestErrorConfig.ts
export const requestErrorConfig = {
  errorConfig: {
    adaptor: (resData) => {
      return {
        success: resData.success,
        errorMessage: resData.errorMessage || '请求失败',
        errorCode: resData.errorCode,
      };
    },
  },
  // 错误处理
  errorHandler: (error) => {
    const { response, message } = error;
    
    if (!response) {
      message.error('网络异常,请检查网络连接');
      return;
    }
    
    // 根据状态码处理不同错误
    switch (response.status) {
      case 401:
        // 未授权,跳转登录页
        history.push('/user/login');
        break;
      case 403:
        message.error('权限不足,无法访问');
        break;
      case 404:
        message.error('请求的资源不存在');
        break;
      case 500:
        message.error('服务器内部错误,请稍后重试');
        break;
      default:
        message.error(`请求错误: ${response.status}`);
    }
  },
};

5.2 错误处理流程

Pro项目的错误处理流程如下:

mermaid

5.3 业务组件错误处理

在页面组件中,应针对特定业务场景处理错误:

// pages/table-list/index.tsx 示例
const [data, setData] = useState<API.RuleListItem[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);

const fetchData = async () => {
  setLoading(true);
  setError(null);
  try {
    const response = await rule({ current: 1, pageSize: 10 });
    setData(response.data || []);
  } catch (err) {
    // 特定业务错误处理
    if (err.errorCode === 'E201') {
      setError('规则列表不存在,请先创建规则');
    } else {
      setError('获取规则列表失败,请重试');
    }
  } finally {
    setLoading(false);
  }
};

// 渲染错误状态
{error && (
  <Alert message="操作失败" description={error} type="error" showIcon />
)}

六、认证与授权

6.1 认证机制实现

Pro项目采用JWT(JSON Web Token)认证机制,实现如下:

// 登录并存储令牌
export async function login(body: API.LoginParams) {
  const response = await request<API.LoginResult>('/api/login/account', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    data: body,
  });
  
  // 存储令牌
  if (response.token) {
    localStorage.setItem('token', response.token);
    // 设置过期时间
    const expireTime = Date.now() + 24 * 60 * 60 * 1000; // 24小时
    localStorage.setItem('tokenExpire', expireTime.toString());
  }
  
  return response;
}

6.2 请求拦截器添加认证信息

// 请求拦截器中添加认证令牌
request.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  const expireTime = localStorage.getItem('tokenExpire');
  
  // 检查令牌是否过期
  if (token && expireTime && Date.now() > Number(expireTime)) {
    // 令牌过期,清除存储
    localStorage.removeItem('token');
    localStorage.removeItem('tokenExpire');
    // 跳转到登录页
    history.push('/user/login');
    return Promise.reject(new Error('会话已过期,请重新登录'));
  }
  
  // 添加令牌到请求头
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  
  return config;
});

6.3 基于RBAC的权限控制

Pro项目通过src/access.ts实现基于角色的访问控制(RBAC):

// src/access.ts
export default function access(initialState: { currentUser?: API.CurrentUser }) {
  const { currentUser } = initialState || {};
  
  return {
    // 管理员权限
    canAdmin: currentUser && currentUser.access === 'admin',
    // 编辑权限
    canEdit: currentUser && ['admin', 'editor'].includes(currentUser.access!),
    // 查看权限
    canView: currentUser && ['admin', 'editor', 'viewer'].includes(currentUser.access!),
  };
}

在组件中使用权限控制:

// 使用Access组件控制渲染
<Access accessible={access.canEdit} fallback={<div>无编辑权限</div>}>
  <Button type="primary" onClick={handleEdit}>编辑</Button>
</Access>

七、性能优化策略

7.1 请求缓存实现

对于不频繁变化的数据,Pro项目建议实现请求缓存:

// 带缓存的API请求(Pro项目建议实现)
import { cache } from 'umi';

// 设置5分钟缓存
export async function getConfig() {
  return cache.fetch('/api/config', async () => {
    return request<API.Config>('/api/config', { method: 'GET' });
  }, { ttl: 5 * 60 * 1000 });
}

7.2 请求合并与防抖

对于频繁触发的请求(如搜索),应使用防抖优化:

// 防抖搜索实现
import { debounce } from 'lodash';

// 创建防抖函数,延迟300ms执行
const debouncedSearch = debounce(async (keyword) => {
  return request<API.SearchResult>(`/api/search?q=${keyword}`, { method: 'GET' });
}, 300);

// 组件中使用
const handleSearch = async (value) => {
  setSearching(true);
  try {
    const result = await debouncedSearch(value);
    setSearchResult(result.data);
  } finally {
    setSearching(false);
  }
};

7.3 批量请求处理

对于多个独立请求,可使用Promise.all并行处理:

// 并行请求优化
async function fetchDashboardData() {
  setLoading(true);
  try {
    // 并行请求多个接口
    const [stats, recentOrders, notifications] = await Promise.all([
      getDashboardStats(),
      getRecentOrders(),
      getNotifications(),
    ]);
    
    setStats(stats.data);
    setOrders(recentOrders.data);
    setNotifications(notifications.data);
  } catch (error) {
    message.error('获取仪表盘数据失败');
  } finally {
    setLoading(false);
  }
}

八、安全最佳实践

8.1 XSS防护

Pro项目通过以下措施防止跨站脚本攻击(XSS):

  1. 使用React的JSX自动转义机制
  2. 对用户输入进行严格验证
  3. 设置适当的Content-Security-Policy
// API请求中验证输入(Pro项目建议实现)
export async function createComment(data: { content: string }) {
  // 简单的XSS过滤
  const safeContent = data.content
    .replace(/<script.*?>.*?<\/script>/gi, '')
    .replace(/onerror=.*?/gi, '');
    
  return request<API.Comment>('/api/comments', {
    method: 'POST',
    data: { ...data, content: safeContent },
  });
}

8.2 CSRF防护

Pro项目通过以下方式防止跨站请求伪造(CSRF):

// 请求拦截器中添加CSRF令牌(Pro项目建议实现)
request.interceptors.request.use((config) => {
  // 从cookie获取CSRF令牌
  const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*=\s*([^;]*).*$)|^.*$/, '$1');
  
  if (csrfToken) {
    // 添加到请求头
    config.headers['X-XSRF-TOKEN'] = csrfToken;
  }
  
  return config;
});

8.3 敏感数据处理

对于敏感数据,应采取加密传输和存储:

// 敏感数据加密传输(Pro项目建议实现)
import CryptoJS from 'crypto-js';

export async function submitPayment(data: API.PaymentInfo) {
  // 加密敏感信息
  const encryptedCardNumber = CryptoJS.AES.encrypt(
    data.cardNumber, 
    process.env.REACT_APP_ENCRYPT_KEY!
  ).toString();
  
  // 移除原始敏感数据
  const safeData = {
    ...data,
    cardNumber: encryptedCardNumber,
    cvv: undefined, // 不在前端存储CVV
  };
  
  return request<API.PaymentResult>('/api/payments', {
    method: 'POST',
    data: safeData,
  });
}

九、API文档与测试

9.1 API文档生成

Pro项目推荐使用Swagger/OpenAPI生成API文档:

// src/services/swagger/index.ts
import { request } from 'umi';

/**
 * @description: 获取宠物列表
 * @param {number} page - 页码
 * @param {number} pageSize - 每页条数
 * @return {API.Pet[]} 宠物列表
 */
export async function getPets(page = 1, pageSize = 10) {
  return request<API.PetList>('/api/pets', {
    method: 'GET',
    params: { page, pageSize },
  });
}

9.2 API测试策略

Pro项目使用Jest和React Testing Library进行API测试:

// src/pages/user/login/login.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import Login from './index';
import { login } from '../../../services/ant-design-pro/api';

// 模拟API
jest.mock('../../../services/ant-design-pro/api');

describe('Login Page', () => {
  test('login successfully with correct credentials', async () => {
    // 模拟登录成功
    (login as jest.Mock).mockResolvedValue({ 
      status: 'ok', 
      currentAuthority: 'admin' 
    });
    
    render(<Login />);
    
    // 输入账号密码
    fireEvent.change(screen.getByPlaceholderText('用户名'), {
      target: { value: 'admin' },
    });
    fireEvent.change(screen.getByPlaceholderText('密码'), {
      target: { value: '123456' },
    });
    
    // 点击登录
    fireEvent.click(screen.getByRole('button', { name: /登录/i }));
    
    // 验证登录成功
    await waitFor(() => {
      expect(login).toHaveBeenCalledWith({
        username: 'admin',
        password: '123456',
      });
      expect(screen.queryByText('用户名或密码错误')).not.toBeInTheDocument();
    });
  });
});

十、实战案例:完整CRUD接口实现

10.1 需求分析

实现一个"用户管理"模块,包含以下功能:

  • 用户列表查询(分页、搜索、筛选)
  • 创建新用户
  • 更新用户信息
  • 删除用户
  • 查看用户详情

10.2 API设计

接口方法描述参数响应
/api/usersGET获取用户列表current, pageSize, keyword, status用户列表分页数据
/api/usersPOST创建用户用户信息创建的用户信息
/api/users/{id}GET获取用户详情id用户详细信息
/api/users/{id}PUT更新用户id, 用户信息更新后的用户信息
/api/users/{id}DELETE删除用户id操作结果

10.3 接口实现

// src/services/ant-design-pro/user.ts(Pro项目建议添加)
import { request } from 'umi';

/** 获取用户列表 GET /api/users */
export async function getUsers(
  params: {
    current?: number;
    pageSize?: number;
    keyword?: string;
    status?: number;
  },
  options?: { [key: string]: any },
) {
  return request<API.PageResponse<API.User>>('/api/users', {
    method: 'GET',
    params: { ...params },
    ...(options || {}),
  });
}

/** 获取用户详情 GET /api/users/{id} */
export async function getUser(id: number, options?: { [key: string]: any }) {
  return request<API.User>(`/api/users/${id}`, {
    method: 'GET',
    ...(options || {}),
  });
}

/** 创建用户 POST /api/users */
export async function createUser(
  data: API.UserForm,
  options?: { [key: string]: any },
) {
  return request<API.User>('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    data,
    ...(options || {}),
  });
}

/** 更新用户 PUT /api/users/{id} */
export async function updateUser(
  id: number,
  data: API.UserForm,
  options?: { [key: string]: any },
) {
  return request<API.User>(`/api/users/${id}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    data,
    ...(options || {}),
  });
}

/** 删除用户 DELETE /api/users/{id} */
export async function deleteUser(id: number, options?: { [key: string]: any }) {
  return request<API.Response>(`/api/users/${id}`, {
    method: 'DELETE',
    ...(options || {}),
  });
}

10.4 类型定义

// src/services/ant-design-pro/typings.d.ts 补充
declare namespace API {
  // 用户信息
  type User = {
    id?: number;
    username?: string;
    name?: string;
    email?: string;
    phone?: string;
    status?: number;  // 1: 启用, 0: 禁用
    avatar?: string;
    role?: string;
    createdAt?: string;
    updatedAt?: string;
  };
  
  // 用户表单数据
  type UserForm = {
    username: string;
    name: string;
    email: string;
    phone?: string;
    password?: string;
    status?: number;
    role?: string;
  };
  
  // 分页响应
  type PageResponse<T> = {
    data: T[];
    total: number;
    current: number;
    pageSize: number;
    success?: boolean;
  };
  
  // 基础响应
  type Response = {
    success?: boolean;
    message?: string;
    errorCode?: string;
  };
}

10.5 组件使用示例

// pages/user/index.tsx(用户列表页面)
import { useEffect, useState } from 'react';
import { Table, Button, Input, Space, Tag, message } from 'antd';
import { SearchOutlined, PlusOutlined } from '@ant-design/icons';
import { getUsers, deleteUser } from '../../services/ant-design-pro/user';
import type { API } from '../../services/ant-design-pro/typings';
import { useAccess, Access } from 'umi';

export default function UserList() {
  const [dataSource, setDataSource] = useState<API.User[]>([]);
  const [loading, setLoading] = useState<boolean>(false);
  const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
  const [keyword, setKeyword] = useState('');
  const access = useAccess();
  
  // 获取用户列表
  const fetchUsers = async () => {
    setLoading(true);
    try {
      const response = await getUsers({
        current: pagination.current,
        pageSize: pagination.pageSize,
        keyword,
      });
      
      setDataSource(response.data || []);
      setPagination({
        ...pagination,
        total: response.total || 0,
      });
    } catch (error) {
      message.error('获取用户列表失败');
    } finally {
      setLoading(false);
    }
  };
  
  // 初始加载和分页变化时获取数据
  useEffect(() => {
    fetchUsers();
  }, [pagination.current, pagination.pageSize]);
  
  // 搜索处理
  const handleSearch = () => {
    setPagination({ ...pagination, current: 1 }); // 重置到第一页
    fetchUsers();
  };
  
  // 删除用户
  const handleDelete = async (id: number) => {
    if (window.confirm('确定要删除此用户吗?')) {
      try {
        await deleteUser(id);
        message.success('删除成功');
        fetchUsers(); // 重新加载数据
      } catch (error) {
        message.error('删除失败');
      }
    }
  };
  
  // 表格列定义
  const columns = [
    {
      title: '用户名',
      dataIndex: 'username',
      key: 'username',
    },
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: '邮箱',
      dataIndex: 'email',
      key: 'email',
    },
    {
      title: '电话',
      dataIndex: 'phone',
      key: 'phone',
      render: phone => phone || '-',
    },
    {
      title: '状态',
      dataIndex: 'status',
      key: 'status',
      render: status => (
        <Tag color={status === 1 ? 'green' : 'red'}>
          {status === 1 ? '启用' : '禁用'}
        </Tag>
      ),
    },
    {
      title: '角色',
      dataIndex: 'role',
      key: 'role',
    },
    {
      title: '操作',
      key: 'action',
      render: (_, record) => (
        <Space size="middle">
          <a onClick={() => handleEdit(record.id)}>编辑</a>
          <Access accessible={access.canAdmin}>
            <a 
              onClick={() => handleDelete(record.id)} 
              style={{ color: '#f5222d' }}
            >
              删除
            </a>
          </Access>
        </Space>
      ),
    },
  ];
  
  return (
    <div className="page-container">
      <div className="page-header" style={{ marginBottom: 16 }}>
        <Space size="middle">
          <Input
            placeholder="输入用户名或姓名搜索"
            value={keyword}
            onChange={e => setKeyword(e.target.value)}
            style={{ width: 300 }}
            suffix={<SearchOutlined onClick={handleSearch} />}
          />
          <Access accessible={access.canEdit}>
            <Button 
              type="primary" 
              icon={<PlusOutlined />}
              onClick={() => history.push('/user/create')}
            >
              添加用户
            </Button>
          </Access>
        </Space>
      </div>
      
      <Table
        columns={columns}
        dataSource={dataSource.map(item => ({ ...item, key: item.id }))}
        loading={loading}
        pagination={{
          ...pagination,
          showSizeChanger: true,
          showQuickJumper: true,
          showTotal: total => `共 ${total} 条记录`,
        }}
        onChange={({ current, pageSize }) => {
          setPagination({ ...pagination, current, pageSize });
        }}
      />
    </div>
  );
}

十一、部署与监控

11.1 API环境配置

Pro项目通过环境变量区分不同环境的API地址:

// .env.development
REACT_APP_API_BASE_URL=/api

// .env.production
REACT_APP_API_BASE_URL=https://api.example.com

// .env.test
REACT_APP_API_BASE_URL=https://api-test.example.com

在请求中使用环境变量:

// src/services/ant-design-pro/api.ts
export async function getUser(id: number) {
  return request<API.User>(`${process.env.REACT_APP_API_BASE_URL}/users/${id}`, {
    method: 'GET',
  });
}

11.2 API监控与埋点

Pro项目建议集成监控工具跟踪API性能:

// API性能监控(Pro项目建议实现)
import * as Sentry from '@sentry/react';

// 请求拦截器中添加性能监控
request.interceptors.request.use((config) => {
  // 记录请求开始时间
  config.__startTime = Date.now();
  
  // 添加Sentry跟踪
  config.__sentryTraceId = Sentry.getCurrentHub().getScope()?.getTransaction()?.traceId;
  
  return config;
});

// 响应拦截器中记录性能
request.interceptors.response.use(
  (response) => {
    // 计算请求耗时
    const duration = Date.now() - response.config.__startTime;
    
    // 记录性能指标
    if (duration > 1000) { // 慢请求阈值:1秒
      console.warn(`Slow API: ${response.config.url}, Duration: ${duration}ms`);
      
      // 上报慢请求到监控系统
      Sentry.addBreadcrumb({
        category: 'api',
        message: `Slow API: ${response.config.url}`,
        data: { 
          duration,
          url: response.config.url,
          method: response.config.method,
          status: response.status,
        },
        level: 'warning',
      });
    }
    
    return response;
  },
  (error) => {
    // 错误上报
    Sentry.captureException(error);
    return Promise.reject(error);
  }
);

十二、总结与展望

12.1 关键知识点回顾

本文系统介绍了Ant Design Pro项目中RESTful API设计的各个方面,包括:

  1. RESTful核心原则:资源标识、HTTP方法映射、状态码使用
  2. Pro项目架构:请求封装、类型定义、拦截器配置
  3. 请求/响应设计:参数规范、数据结构、错误处理
  4. 安全与性能:认证授权、数据加密、请求优化
  5. 实战案例:完整CRUD接口的设计与实现

12.2 进阶方向

  1. GraphQL集成:考虑使用GraphQL优化多资源查询场景
  2. API版本控制:实现API版本管理策略(如/api/v1/resource
  3. WebSocket实时通信:对于实时数据需求,集成WebSocket
  4. 自动化测试:完善API自动化测试覆盖
  5. 接口性能监控:建立API性能基准和报警机制

12.3 最佳实践清单

为确保API设计质量,建议遵循以下清单:

  •  所有API路径使用名词复数形式
  •  HTTP方法与CRUD操作正确映射
  •  实现统一的响应格式和错误处理
  •  使用TypeScript定义所有请求/响应类型
  •  为所有API添加详细注释
  •  实现请求参数验证
  •  配置适当的缓存策略
  •  添加请求/响应日志
  •  实现完善的认证与授权
  •  定期进行API性能分析和优化

通过遵循本文介绍的规范和最佳实践,你将能够构建出高质量、可维护、安全高效的API接口,显著提升前后端协作效率和用户体验。


如果你觉得本文对你有帮助,请点赞、收藏并关注,下期我们将深入探讨Ant Design Pro的状态管理最佳实践!

【免费下载链接】ant-design-pro 👨🏻‍💻👩🏻‍💻 Use Ant Design like a Pro! 【免费下载链接】ant-design-pro 项目地址: https://gitcode.com/gh_mirrors/an/ant-design-pro

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值