4.2 KiB
4.2 KiB
9.4 HTTP 请求封装
:::tip 概述 前端使用 Axios 封装 HTTP 请求,自动处理 Token 携带、响应码判断与错误提示(401 时提示重新登录)。 :::
封装结构
ui/src/utils/http/axios/
├── index.ts # Axios 实例配置和拦截器
├── Axios.ts # VAxios 类封装
├── axiosCancel.ts # 请求取消
├── axiosTransform.ts # 数据转换接口
├── checkStatus.ts # HTTP 状态码处理
├── helper.ts # 辅助函数
└── types.ts # 类型定义
核心拦截器
请求拦截器(自动携带 Token)
// ui/src/utils/http/axios/index.ts
// 请求前自动添加 Token(storage 键名 'ACCESS-TOKEN')
const token = storage.get('ACCESS-TOKEN', '');
config.headers['Authorization'] = `Bearer ${token}`;
响应拦截器(统一错误处理)
// 响应处理逻辑
const { code, data, msg } = res.data;
if (code === 0) {
return data; // 成功,返回 data(拦截器已解包)
}
if (code === 401 || res.status === 401) {
// Token 过期 → 弹窗提示 → storage.clear() → 跳转登录(见下方 401 处理)
}
if (code === 403 || res.status === 403) {
// 权限不足 / 租户异常 / 演示模式拦截
message.error(msg || '无访问权限');
}
// 其他业务错误,显示提示
message.error(msg || '操作失败');
:::tip 响应处理规则
code === 0:成功,返回datacode/status === 401:Token 过期,弹窗提示重新登录 → 清除本地存储 → 跳转登录页code/status === 403:权限不足,显示错误提示(msg含权限码或拦截原因)- 其它
code:业务失败,显示msg(1=业务/FormRequest 错误、404=数据不存在、422=手动校验、500=服务器异常) - HTTP 状态码约定见 8.1 统一响应格式 :::
401 处理(实际实现,摘自 ui/src/utils/http/axios/index.ts)
// code === 401(ResultEnum.TIMEOUT)
case ResultEnum.TIMEOUT:
if (router.currentRoute.value?.name === PageEnum.BASE_LOGIN_NAME) return;
Modal.warning({
title: '提示',
content: '登录身份已失效,请重新登录!',
closable: false,
maskClosable: false,
okText: '确定',
onOk: () => {
storage.clear();
window.location.href = PageEnum.BASE_LOGIN; // '/login'
},
});
break;
:::info 自动续签能力在后端
ui/ 当前未内置自动续签(401 直接重新登录)。后端 POST /api/refresh 刷新能力完整保留,详见 5.2 认证流程实战 与 8.6 Token 使用说明。
:::
API 模块编写
// ui/src/api/tool/example.ts
import { http } from '@/utils/http/axios';
export function getExamplePage(params?: Record<string, any>) {
return http.request({
url: '/example/page',
method: 'GET',
params,
});
}
export function exampleAdd(data: any) {
return http.request({
url: '/example/add',
method: 'POST',
data,
});
}
// 注意:批量删除为 DELETE(请求体 { ids: [] })
export function exampleBatchDelete(data: any) {
return http.request({
url: '/example/batchDelete',
method: 'DELETE',
data,
});
}
(完整规范见 9.13 API 模块编写规范。)
在组件中使用
import { getExamplePage, exampleAdd } from '@/api/tool/example';
// 获取列表(res 已是 data 部分)
const res = await getExamplePage({ pageNo: 1, pageSize: 10 });
tableData.value = res.records; // { records, total, current, size }
total.value = res.total;
// 新增
await exampleAdd({ name: '测试', status: 1 });
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 所有请求 401 | Token 未携带 / 已过期 | 检查拦截器与登录态;401 弹窗确认后清存储并跳登录页 |
| 请求 404 | URL 与后端路由不一致 | 核对 routes/api.php(注意 batchDelete 为 DELETE) |
| 请求跨域 | 直连后端且未配代理/CORS | 用 Vite VITE_PROXY 代理或后端配 CORS_ALLOW_ORIGIN |
| 响应取不到 data | 拦截器未解包 | 统一约定拦截器返回 data;排查是否绕过了 http.request |