9.2 KiB
前端 API 接口格式统一性审查报告
审查时间:2026-06-09 范围:
frontend/下所有源码(unpackage/dist等编译产物已排除) 核心封装器:frontend/utils/api.js的request(options)
0. TL;DR
整体架构是统一的:所有 JSON 接口走同一 request() 入口,token 注入、401 跳转、响应解析、Mock 短路都集中在 utils/api.js。
主要问题不在封装本身,而在一批"绕过封装"的散点:
- OSS 上传/下载没有沉淀到
api.js,导致 5 个页面 + 3 个 utils 各自实现一遍 - 20+ 处业务侧重复判断
code === 200(封装器已保证) - 2 处历史遗留 URL 仍走旧版
/api/user/*(无/v1) - 3 个模块 自己造了
request风格的uni.request轮子
优先级 P0:把 OSS 直传抽到 utils/api.js,可一次性消掉 30+ 处重复代码。
1. 已统一的良好部分 ✅
1.1 入口封装 — 95% 的 JSON 接口走 request()
- 唯一封装器:
frontend/utils/api.js的request(options)(L53–L134) frontend/utils/api.js内 60+ 个 API +frontend/utils/task-api.js的 11 个 API 全部走request()- 全项目 46 个文件 直接 import
@/utils/api或@/utils/task-api,无相对路径污染
1.2 Token 注入
- 自动从
uni.getStorageSync('access_token')读取 - Header 格式统一为
Authorization: Bearer <token> - 白名单(不注入 token):
/api/v1/auth/login|register|send-code|verify-code
1.3 业务响应结构
后端约定:{ code, message, data },封装器在 request() 内统一处理:
| 输入 | 行为 |
|---|---|
HTTP 200/202 + code === 200 |
resolve 整体响应 |
HTTP 200/202 + code === 401/400/403 |
清 token + 跳登录 + reject |
HTTP 200/202 + 其他 code |
reject(Error(message)) |
HTTP 200/202 + 无 code 字段 |
resolve(res.data) ← 兜底 |
HTTP 401 |
清 token + 跳登录 + reject |
| 其他 HTTP 状态码 | reject(`Error(message |
1.4 环境与 Mock 开关
VITE_API_BASE_URL/VITE_USE_MOCK_API集中读取IS_MOCK_API暴露给业务做短路getWebSocketBaseUrl/getSegmentApiBaseUrl/getLaserApiBaseUrl三个 baseURL 工厂统一
1.5 Dashboard 模块有专门封装
dashboardApi 对象 + dashboardRequest() 工厂(utils/api.js L999–L1007),统一了 mock 短路与 baseURL 前缀。
1.6 WebSocket 入口统一
utils/socket/SocketManager.js 通过 getWebSocketBaseUrl() 工厂函数拿到 baseURL(L48–L49),token 拼在 query 上(?token=Bearer_<token>),鉴权方式与 HTTP 通道保持一致。
2. 不一致点(按严重度排序)
🔴 严重:页面层直连 uni.request / uni.uploadFile / fetch
下列文件绕过了 request() 封装,需要各自维护 token 注入、超时、错误处理、401 跳转。表中行号定位到调用点。
| 文件 | 行号 | 用途 | 风险点 |
|---|---|---|---|
pages/discover/discover.vue |
L101, L134 | OSS PostObject | 重复实现 fetch + uploadFile 分支 |
pages/discover/generation-result.vue |
L316, L418, L495, L653 | OSS + 上传 | 4 处独立直传,逻辑高度相似 |
pages/castlove/index.vue |
L261, L409 | 图片下载/上传 | 自行处理 token |
pages/castlove/create.vue |
L430, L527, L540, L569, L614 | 全链路直传 | 5 处,逻辑重复 |
pages/castlove/lenticular/lenticular-create.vue |
L331, L427, L440, L468, L512 | 全链路直传 | 5 处 |
pages/castlove/lenticular/lenticular-result.vue |
L217, L319, L396, L554 | 全链路直传 | 4 处 |
pages/square/components/WaterfallGrid.vue |
L712, L735, L777, L832 | 业务请求 | 4 处 res.code === 200 |
pages/square/components/HotCategoryBlock.vue |
L193 | 业务请求 | code === 200 重复判断 |
pages/profile/profile.vue |
L1187 | 头像上传 | 自处理 statusCode |
pages/profile/setNickname.vue |
L183 | 头像上传 | 自处理 statusCode,无 token 注入 |
pages/starbook/items.vue |
L136 | 业务请求 | response.code === 200 |
🟡 中等:业务侧重复判断 code === 200
request() 已经对 code === 200 resolve 整体,业务侧不应再判断。下列位置违反封装契约:
utils/progress-manager.js:180
utils/activity-config.js:46, 69, 87, 105, 126
utils/craftMintSubmit.js:481, 510, 627, 690
pages/square/components/WaterfallGrid.vue:712, 735, 777, 832
pages/square/components/HotCategoryBlock.vue:193
pages/starbook/items.vue:136
pages/discover/discover.vue:195, 223
pages/discover/generation-result.vue:284
composables/useLaserMint.js:42
🟡 中等:部分模块自己造 request 风格轮子
| 文件 | 位置 | 说明 |
|---|---|---|
composables/useLaserDifyGenerate.js |
L19–L47 | 独立 laserRequest(),自行注入 token、超时、状态码判断,文件内注释自承 "返回格式与 api.js 的 request() 一致" |
utils/laser-card/segmentationCloud.js |
L21–L39 | uniRequest() 重复实现,仅做状态码判断 |
utils/laser-card/aliyunPortraitUni.js |
L273 | uni.request 走 OSS PostObject,因 OSS 协议需要单独处理 x-oss-date 等特殊头 |
utils/craftMintSubmit.js |
L21, L57, L70, L399, L407, L423, L451 | 5 处 uni.uploadFile/fetch 混用,H5/App 分支自管 |
这些位置有合理理由绕过
request()(OSS 直传需自定义头、需multipart/form-data),但应抽到utils/api.js而不是散布在业务模块。
🟡 中等:URL 风格不一致
虽然都带 /api/v1 前缀,但功能模块 URL 风格混乱:
- 资源 URL:
/api/v1/mygalleries(无/me也没有/users)vs/api/v1/galleries/:uidvs/api/v1/galleries/random(utils/api.jsL431–L452) - 历史遗留:
updateUserInfoApiL215 仍走/api/user/update(无/v1),deleteAccountApiL276 走/api/user/delete-account - 单复数、是否用
/me表示当前用户不统一:/api/v1/auth/me/api/v1/me/nickname/api/v1/me/avatar/api/v1/me/liked-assets/api/v1/me/exhibited-assets/api/v1/users/:uid/liked-assets
🟢 轻微:拼装 URL 的方式不统一
- 多数用模板字符串拼在
url内(/api/v1/social/users?page=${page}&page_size=${pageSize},utils/api.jsL226) - 也有用
data字段传 query 的(GET 请求,如task-api.jsL15getDailyTasks把star_id放data字段,uni.request 在 GET 下会拼到 query) - 统一规范缺失,新人很容易混用
🟢 轻微:request 默认 timeout 与 uni.uploadFile 超时不一致
request()默认 60000ms(L78)segmentPortraitApi用 120000ms(L749)downloadToLocal用 120000ms(composables/useLaserSegment.jsL29)- 没有集中常量
3. 统计摘要
| 指标 | 数值 |
|---|---|
直接 import @/utils/api 的文件 |
46 |
仍走 uni.request 直连的文件 |
7 |
仍走 uni.uploadFile 直连的文件 |
8 |
仍走 fetch() 直连的文件 |
5 |
业务侧 code === 200 二次判断处 |
20+ |
URL 路径里残留 /api/user/* 旧接口 |
2 |
重复实现的 request 风格封装 |
3(laserRequest、uniRequest、laserRequest) |
4. 修复建议(按 ROI 排序)
P0 — 把"绕过封装"的 OSS 直传抽到 api.js
新增一组 OSS 专用工具到 utils/api.js:
// 上传 OSS (H5: fetch + FormData / App: uni.uploadFile)
export function uploadToOss({ host, dir, filePath, policy, signature, ... }) { ... }
// 下载 OSS (H5: fetch + blob URL / App: uni.downloadFile)
export function downloadFromOss(signedUrl) { ... }
收益:消掉 5 个页面、3 个 utils 中重复的 30+ 处直传代码;统一 token 注入;统一超时;统一错误处理。
P1 — 修复 /api/user/* 旧路径
updateUserInfoApi(L215):/api/user/update→ 对应的 v1 路径deleteAccountApi(L276):/api/user/delete-account→/api/v1/me/account之类
P1 — 业务侧禁用 code === 200 二次判断
封装器已经处理,业务层应只 try/catch。可在 request() 里加注释:
// 业务侧请勿重复判断 code === 200,封装器已保证 resolve 时 code === 200
P2 — URL 风格规范化
建议对齐:
- 当前用户 →
/me(已用):/api/v1/me/liked-assets、/api/v1/me/exhibited-assets等等 - 指定用户 →
/users/:uid:/api/v1/users/:uid/liked-assets - 收藏/资源 → 单数主语,操作作子路径:
/api/v1/galleries/...而不是/api/v1/mygalleries
P2 — 提取 api.js 默认 timeout 常量
const DEFAULT_TIMEOUT = 60000
const UPLOAD_TIMEOUT = 120000
export const API_TIMEOUT = {
default: DEFAULT_TIMEOUT,
upload: UPLOAD_TIMEOUT,
download: UPLOAD_TIMEOUT,
}
P3 — 拼装 query 的工具函数
export function buildQuery(params) {
return '?' + new URLSearchParams(params).toString()
}
让所有 getXxxApi 走同一方式,而非分散在 url/data 两处。
5. 后续 Action Items
| 优先级 | 任务 | 涉及文件数 | 预估工时 |
|---|---|---|---|
| P0 | 把 OSS 上传/下载抽到 utils/api.js |
8 | 4h |
| P1 | 修复 /api/user/* 旧路径 |
2 | 0.5h |
| P1 | 业务侧清除 20+ 处 code === 200 二次判断 |
10+ | 1h |
| P2 | URL 风格规范化 + /me 对齐 |
20+ | 2h |
| P2 | 提取 API_TIMEOUT 常量 |
3 | 0.5h |
| P3 | 引入 buildQuery 工具函数 |
30+ | 1h |