接口接入
纯前端商业版不要求客户后端复刻某一套固定技术栈,但前端仍需要稳定的认证、响应和错误契约。本章从开发代理开始,说明如何接入最小认证接口,再逐步迁移业务页面。
请求链路
页面 / Store / 路由守卫
-> src/api
-> src/utils/http/index.ts
-> Axios
-> 开发代理或生产网关
-> 客户后端所有 HTTP 接口必须定义在 src/api。页面不应该直接调用 Axios,也不应该把请求函数写进 src/services。统一请求层负责 Token、JSON、响应解包、错误提示和 401 处理,API 模块描述具体 URL、参数、返回类型和必要的单接口字段适配。
环境变量
公共配置
.env 中与接口相关的配置:
# 浏览器请求基础地址
VITE_API_URL = /
# 是否携带跨域 Cookie
VITE_WITH_CREDENTIALS = false
# 菜单来源:local 或 remote
VITE_MENU_SOURCE = local开发环境
推荐通过 Vite 代理联调:
# .env.development
VITE_API_URL = /
VITE_API_PROXY_URL = http://localhost:13000vite.config.ts 会把 /api 和 /uploads 转发到代理目标。
生产环境
推荐优先使用同源网关:
# .env.production
VITE_API_URL = /然后由 Nginx 或网关把 /api 和 /uploads 转发到后端。也可以使用完整地址:
VITE_API_URL = https://api.example.com此时后端必须正确配置 CORS。所有 VITE_ 变量都可以在浏览器构建产物中读取,不能存放任何密钥。
统一响应格式
当前请求层期望:
{
"code": 200,
"msg": "操作成功",
"data": {}
}处理规则:
code === 200:返回data。code === 401:统一清理登录态并跳转登录页。- 其他业务码:转换为
HttpError并按请求配置展示错误。 - HTTP 非 2xx:进入 Axios 错误链路。
如果客户后端响应结构不同,优先在统一请求层做一次适配,不要在每个页面重复读取 response.result、response.payload 等字段。
Axios 配置
请求实例位于 src/utils/http/index.ts,当前关键行为包括:
| 配置 | 当前行为 |
|---|---|
| 超时 | 15 秒 |
| Token | Authorization: Bearer <accessToken> |
| JSON | 非 FormData 请求自动使用 application/json |
| Cookie | 由 VITE_WITH_CREDENTIALS 控制,默认关闭 |
| 成功提示 | 通过 showSuccessMessage 按请求开启 |
| 错误提示 | 默认开启,可用 showErrorMessage: false 关闭 |
| 自动重试 | 当前次数为 0 |
常用调用:
// src/api/order.ts
import request from '@/utils/http'
export function fetchOrderList(params: Api.Order.SearchParams) {
return request.get<Api.Common.PaginatedResponse<Api.Order.ListItem>>({
url: '/api/v1/orders',
params
})
}
export function createOrder(data: Api.Order.CreateParams) {
return request.post<Api.Order.Detail>({
url: '/api/v1/orders',
data,
showSuccessMessage: true
})
}最小认证接口
登录
POST /api/v1/auth/signin请求:
{
"username": "Super",
"password": "123456"
}响应 data:
{
"accessToken": "your-access-token"
}接口函数位于 src/api/auth.ts。当前认证流程会在调用 API 后检查 accessToken 是否为非空字符串。
当前用户
GET /api/v1/user/info
Authorization: Bearer <accessToken>核心字段:
interface UserInfo {
id: number
username: string
email: string
roles: string[]
buttons: string[]
}前端会校验这些字段。如果 buttons 使用通配权限,只能返回:
{ "buttons": ["*"] }不要同时返回 * 和其他权限码。
退出登录
POST /api/v1/auth/logout无论后端退出请求结果如何,前端都应最终清理本地 Token、用户信息和动态路由。后端负责使当前会话或令牌失效。
会话与安全协议
当前实现有意保持标准和简洁:
- 登录密码按 JSON 提交,生产环境必须使用 HTTPS。
- 不内置 RSA 密码加密、请求签名、Nonce 或时间戳。
- 不内置 Refresh Token 协议。
- 收到 401 后不会静默使用 Mock 数据。
- Access Token 持久化,用户资料与权限刷新时重新获取。
如果客户后端需要 Refresh Token,应在 src/api/auth.ts 中定义刷新接口,把刷新和并发请求队列封装在请求层,并由用户状态统一保存和清理令牌。不要让各页面分别处理令牌刷新。
API 目录职责
接口调用统一遵循:
页面 / Store / 可选流程封装
-> src/api/<domain>.ts
-> src/utils/http/index.tssrc/api 是唯一的 HTTP 接口目录:
- 按业务域组织接口文件,例如
src/api/customer/user.ts。 - 一个接口函数描述请求方法、URL、参数和返回类型。
- 后端字段与前端模型不一致时,可以在对应 API 函数中转换。
- 普通 CRUD 页面或 Hook 直接调用 API 模块。
src/services只允许编排多个 API 或封装复杂业务流程,不能定义 URL、Axios 请求或单个后端接口。
当前源码中的 authService 是已有的认证流程包装,它调用 src/api/auth.ts 并校验响应。新增登录、验证码、刷新令牌等 HTTP 接口仍然必须写在 src/api/auth.ts,不能继续堆到 Service 中。
迁移业务页面
1. 定义类型
在 src/types/api/<domain>.d.ts 中定义查询参数、列表项、详情和写入参数。优先复用现有 Api.Common.PaginatedResponse<T>。
2. 创建 API 模块
// src/api/customer/user.ts
import request from '@/utils/http'
export function fetchUserList(params: Api.Identity.UserSearchParams) {
return request.get<Api.Common.PaginatedResponse<Api.Identity.UserListItem>>({
url: '/customer-api/users',
params
})
}3. 替换页面导入
// 迁移前
import { getDemoUserList } from '@/mock/system/organization'
// 迁移后
import { fetchUserList } from '@/api/customer/user'然后把 useTable 的 apiFn 指向新函数。尽量保持参数语义和返回类型一致。
4. 处理响应差异
列表后端常见字段包括 records、list、items、rows。如果只有单个页面格式不同,使用 useTable 的 responseAdapter;如果多个页面统一使用同一格式,再调整全局表格映射。
5. 迁移写操作
写接口完成后替换 showDemoActionNotice,并确认:
- 防止重复提交。
- 成功后刷新正确页面。
- 失败后保留用户输入。
- 403 与业务校验错误文案明确。
- 后端完成资源级鉴权和审计。
文件上传
开发代理已经转发 /uploads,但前端不内置对象存储服务。接入上传时建议:
- 小文件可通过后端接收
FormData。 - 大文件、分片或直传对象存储应由后端签发短期凭证。
- 不要把长期 AccessKey 放入
VITE_变量。 - 下载接口应由后端校验用户对文件的访问权限。
联调检查清单
- 浏览器请求地址是否符合当前环境。
- 代理是否转发
/api和/uploads。 - 响应是否始终包含
code、msg、data。 - Bearer Token 是否正确附加。
- 401 是否清理会话,403 是否由业务后端返回。
- 空列表、慢请求、网络断开和 500 是否有合理界面。
- 未迁移页面是否仍明确使用预置数据。
- 生产构建中是否没有密钥和开发域名。
