本项目参考 JeecgBoot 前端的请求封装方案,提供了完整的 HTTP 请求工具和服务层封装。
src/
├── utils/
│ └── request.ts # 核心请求工具
├── services/
│ ├── api.ts # 系统 API
│ ├── BaseService.ts # 基础服务类
│ ├── index.ts # 统一导出
│ └── modules/ # 业务模块服务
│ ├── user.ts
│ ├── role.ts
│ └── content.ts
└── examples/
└── ApiUsage.tsx # 使用示例
import http from "@/utils/request";
// GET 请求
const users = await http.get("/sys/user/list", { pageNo: 1, pageSize: 10 });
// POST 请求
const result = await http.post("/sys/user/add", { username: "test" });
// PUT 请求
await http.put("/sys/user/edit", { id: "1", username: "updated" });
// DELETE 请求
await http.delete("/sys/user/delete", { id: "1" });
// 文件上传
const formData = new FormData();
formData.append("file", file);
const uploadResult = await http.upload("/sys/common/upload", formData);
// 文件下载
await http.download("/sys/user/exportXls", "用户列表.xls", { status: 1 });
import { sysApi, dictApi, uploadApi } from "@/services";
// 系统 API
const menus = await sysApi.getUserMenus();
const permissions = await sysApi.getUserPermissions();
await sysApi.login({ username: "admin", password: "123456" });
// 字典 API
const dictItems = await dictApi.getDictItems("sex");
// 上传 API
const result = await uploadApi.upload(file);
import { userService, roleService, contentService } from "@/services";
// 分页查询
const userList = await userService.list({
pageNo: 1,
pageSize: 10,
column: "createTime",
order: "desc",
username: "admin", // 查询条件
});
// CRUD 操作
const user = await userService.getById("1");
await userService.add({ username: "newuser" });
await userService.edit({ id: "1", username: "updated" });
await userService.delete("1");
await userService.deleteBatch(["1", "2", "3"]);
// 导入导出
await userService.exportXls({ status: 1 }, "用户列表.xls");
await userService.importExcel(file);
import { createService } from "@/services";
// 为任意模块创建服务
const customService = createService("/api/custom");
const list = await customService.list({ pageNo: 1, pageSize: 10 });
const item = await customService.getById("1");
await customService.add({ name: "test" });
// src/services/modules/department.ts
import { BaseService } from "../BaseService";
import http from "../../utils/request";
export interface Department {
id: string;
departName: string;
parentId?: string;
orgCode?: string;
}
class DepartmentService extends BaseService<Department> {
constructor() {
super("/sys/sysDepart"); // 基础路径
}
// 自定义方法
queryTreeList() {
return http.get<Department[]>("/sys/sysDepart/queryTreeList");
}
searchBy(keyword: string) {
return http.get<Department[]>("/sys/sysDepart/searchBy", { keyword });
}
}
export const departmentService = new DepartmentService();
export default departmentService;
export { default as departmentService } from "./modules/department";
export type { Department } from "./modules/department";
// 跳过全局错误处理
const data = await http.get(
"/api/check",
{ username: "test" },
{ skipErrorHandler: true }
);
// 自定义超时时间
const data = await http.post(
"/api/long-task",
{ data: "..." },
{ timeout: 60000 } // 60秒
);
// 自定义请求头
const data = await http.get(
"/api/data",
{},
{
headers: {
"Custom-Header": "value",
},
}
);
import { TokenManager } from "@/services";
// 获取 Token
const token = TokenManager.getToken();
// 设置 Token
TokenManager.setToken("your-token");
// 删除 Token
TokenManager.removeToken();
// 单文件上传
import { uploadApi } from "@/services";
const handleUpload = async (file: File) => {
const result = await uploadApi.upload(file);
console.log("文件地址:", result.url);
};
// 批量上传
const handleBatchUpload = async (files: File[]) => {
const result = await uploadApi.uploadBatch(files);
console.log("文件地址列表:", result.urls);
};
// 导出 Excel
await userService.exportXls(
{
status: 1,
createTime_begin: "2024-01-01",
createTime_end: "2024-12-31",
},
"用户列表.xls"
);
// 导入 Excel
const handleImport = async (file: File) => {
const result = await userService.importExcel(file);
console.log("导入结果:", result);
};
import type { PageParams, PageResult } from "@/services";
const queryUsers = async () => {
const params: Partial<PageParams> = {
pageNo: 1,
pageSize: 10,
column: "createTime", // 排序字段
order: "desc", // 排序方式
// 查询条件
username: "admin",
status: 1,
createTime_begin: "2024-01-01",
createTime_end: "2024-12-31",
};
const result: PageResult<User> = await userService.list(params);
console.log("总记录数:", result.total);
console.log("总页数:", result.pages);
console.log("当前页:", result.current);
console.log("每页大小:", result.size);
console.log("数据列表:", result.records);
};
{
"success": true,
"message": "操作成功",
"code": 200,
"result": {
// 实际数据
},
"timestamp": 1638888888888
}
{
"success": true,
"message": "查询成功",
"code": 200,
"result": {
"records": [...],
"total": 100,
"size": 10,
"current": 1,
"pages": 10
}
}
系统会自动处理以下错误:
try {
const data = await http.get("/api/data", {}, { skipErrorHandler: true });
// 处理成功
} catch (error) {
// 自定义错误处理
console.error("请求失败:", error.message);
// 显示自定义提示
alert("操作失败,请重试");
}
services/
├── api.ts # 系统级 API(登录、权限等)
├── BaseService.ts # 基础服务类
├── index.ts # 统一导出
└── modules/ # 按业务模块组织
├── user.ts # 用户模块
├── role.ts # 角色模块
├── department.ts # 部门模块
└── content.ts # 内容模块
// 定义接口类型
export interface User {
id: string;
username: string;
realname: string;
// ...
}
// 使用泛型
class UserService extends BaseService<User> {
// TypeScript 会自动推断返回类型
}
// 需要用户感知的错误:使用全局错误处理
await userService.delete(id);
// 不需要用户感知的错误:跳过全局错误处理
try {
await http.get("/api/check", { username }, { skipErrorHandler: true });
// 用户名可用
} catch {
// 用户名已存在
}
const [loading, setLoading] = useState(false);
const handleSubmit = async () => {
try {
setLoading(true);
await userService.add(formData);
// 成功提示
} catch (error) {
// 错误已被全局处理
} finally {
setLoading(false);
}
};
在 .env 文件中配置 API 基础地址:
# 开发环境
VITE_API_BASE_URL=http://localhost:8080
# 生产环境
VITE_API_BASE_URL=https://api.example.com
Token 存储在 localStorage 中,key 为 ACCESS_TOKEN。
在 src/utils/request.ts 中修改 TokenManager.TOKEN_HEADER。
const data = await http.get("/api/data", {}, { timeout: 60000 });
系统会自动检测 content-type,如果是 application/octet-stream 会返回 Blob。
在 src/utils/request.ts 的 requestInterceptor 中添加:
console.log("请求:", config.url, config);
// Axios
axios.get("/api/users", { params: { id: 1 } });
axios.post("/api/users", { username: "test" });
// 本项目
http.get("/api/users", { id: 1 });
http.post("/api/users", { username: "test" });
大部分 API 保持一致,只需要:
this.$http 改为 httpthis.url.xxx 改为服务方法调用使用 async/await 替代 Promise.then
// Vue 版本
this.$http.get(this.url.list, { params: query }).then((res) => {
this.dataSource = res.result.records;
});
// React 版本
const result = await userService.list(query);
setDataSource(result.records);