从零到一:Ant Design Pro RESTful接口设计实战指南
引言:你还在为前后端对接焦头烂额?
在现代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项目中
updateRule和removeRule方法目前使用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请求,确保代码的可维护性和可扩展性:
- 页面组件层:如
pages/table-list/index.tsx,调用API服务层方法 - API服务层:如
services/ant-design-pro/api.ts,定义接口方法 - 请求工具层:基于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项目中请求参数遵循以下规范:
-
查询参数:用于GET请求的过滤、排序和分页
// 分页查询示例 rule({ current: 1, pageSize: 10 }); -
请求体:用于POST/PUT请求的复杂数据
// 登录请求示例 login({ username: 'admin', password: '123456' }); -
路径参数:用于标识特定资源
// 获取单个用户信息(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格式 |
| 数字 | number | 123.45 | 不使用NaN或Infinity |
| 布尔值 | boolean | true | 不使用0/1代替 |
| 数组 | T[] | [1, 2, 3] | 空数组表示无数据 |
| 对象 | object | {name: "foo"} | 空对象表示无数据 |
| 日期 | string | "2024-09-01T12:00:00Z" | 使用UTC时间 |
4.3 状态码设计
Pro项目采用双重状态码机制:
- HTTP状态码:表示请求传输层面的状态
- 业务错误码:表示应用逻辑层面的状态
业务错误码设计规范:
// 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项目的错误处理流程如下:
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):
- 使用React的JSX自动转义机制
- 对用户输入进行严格验证
- 设置适当的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/users | GET | 获取用户列表 | current, pageSize, keyword, status | 用户列表分页数据 |
/api/users | POST | 创建用户 | 用户信息 | 创建的用户信息 |
/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设计的各个方面,包括:
- RESTful核心原则:资源标识、HTTP方法映射、状态码使用
- Pro项目架构:请求封装、类型定义、拦截器配置
- 请求/响应设计:参数规范、数据结构、错误处理
- 安全与性能:认证授权、数据加密、请求优化
- 实战案例:完整CRUD接口的设计与实现
12.2 进阶方向
- GraphQL集成:考虑使用GraphQL优化多资源查询场景
- API版本控制:实现API版本管理策略(如
/api/v1/resource) - WebSocket实时通信:对于实时数据需求,集成WebSocket
- 自动化测试:完善API自动化测试覆盖
- 接口性能监控:建立API性能基准和报警机制
12.3 最佳实践清单
为确保API设计质量,建议遵循以下清单:
- 所有API路径使用名词复数形式
- HTTP方法与CRUD操作正确映射
- 实现统一的响应格式和错误处理
- 使用TypeScript定义所有请求/响应类型
- 为所有API添加详细注释
- 实现请求参数验证
- 配置适当的缓存策略
- 添加请求/响应日志
- 实现完善的认证与授权
- 定期进行API性能分析和优化
通过遵循本文介绍的规范和最佳实践,你将能够构建出高质量、可维护、安全高效的API接口,显著提升前后端协作效率和用户体验。
如果你觉得本文对你有帮助,请点赞、收藏并关注,下期我们将深入探讨Ant Design Pro的状态管理最佳实践!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



