Files
nianxx-h5/.trae/documents/统一请求库封装计划.md
duanshuwen 548df7020c feat: initial project setup with core infrastructure and api clients
- Add environment configs for dev/staging/prod environments
- Implement centralized axios request utility with standardized error handling
- Add shared TypeScript types for API responses and requests
- Create comprehensive API client modules for all core endpoints
- Configure vue router with all application page routes
- Add icon fonts, static assets, and loading animations
- Set up project documentation and collaboration guidelines
- Remove deprecated uni-app bridge component files
2026-05-26 21:42:36 +08:00

206 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 统一请求库封装计划src/utils/request.ts 版)
## Summary
目标:把统一请求库集中封装在 `src/utils/request.ts`,类型集中在 `src/shared/`,实现:
- baseURL/timeout/取消请求Axios Web
- 默认 header 注入AuthorizationBearer、clientId、X-Latitude、X-Longitude、language
- 业务错误/网络错误/HTTP 错误的统一归一化(只抛错,不做 Toast/跳转)
- 输出说明文档到 `docs/request.md`
## Current State Analysis以实际仓库为准
已确认的事实:
- 依赖中已包含 `axios`,但 `src/` 内暂无 axios 的实际封装与使用。
- `src/utils/request.ts` 存在但为空文件,且命名疑似历史遗留。
- 代码中存在大量“缺失模块引用”(详见文末“历史遗留问题清单”),其中 `@/request/api/*` 属于最集中、最影响后续迁移的一类。
结论:
- 本次统一请求库规划要做到“新增即可用、可渐进替换”不依赖现有缺失的API 模块结构。
## Assumptions & Decisions你已确认
- 底层实现AxiosWeb
- baseURL`import.meta.env` 的环境变量读取(本计划固定变量名为 `VITE_API_BASE_URL`
- header 值来源:全局上下文注入(内存态),由登录/定位/语言切换时写入
- Authorization`Bearer <token>`token 为空则不带 Authorization
- 错误处理:请求库只做错误标准化并抛错,不做 Toast/跳转
- header 字段:`Authorization``clientId``X-Latitude``X-Longitude``language`
## 为什么不拆得更细(回答你的问题)
可以都放在 `src/utils/request.ts` 里完成,且更适合你现在“先落地一个可用的统一入口”的诉求:
- 单文件落地成本低:少目录、少入口、少导出点,替换/回滚都更直接
- 不牺牲可维护性:在单文件里用“内部分区函数 + 类型从 shared 引入”的方式,同样能保持边界清晰
- 何时再拆分:当出现“单文件 > 300~500 行、多人同时改动频繁、需要独立单测/Mock”的情况再把 errors/context/http 拆出去更合理
因此本计划采用:**实现集中在 request.ts类型抽到 shared** 的折中方案。
## Proposed Changes全新规划
### 1) 新增类型目录:`src/shared/`
新增目录:`src/shared/`
新增文件(建议):
- `src/shared/request-types.ts`
包含的类型定义(稳定、可复用):
- `export interface ApiResponse<T> { code: number; message?: string; data: T }`
- `export interface RequestOptions { signal?: AbortSignal; headers?: Record<string, string>; skipAuth?: boolean }`
- `export type RequestContext = { token: string | null; clientId: string | null; latitude: number | null; longitude: number | null; language: string | null }`
- `export type NormalizedErrorKind = "business" | "http" | "network" | "unknown"`
- `export interface NormalizedError extends Error { kind: NormalizedErrorKind; code?: number; httpStatus?: number; response?: unknown }`
### 2) 统一请求实现:`src/utils/request.ts`
新增文件:`src/utils/request.ts`
职责(全部在一个文件内完成):
#### 2.1 上下文容器(内存态)
提供以下导出函数(由业务在合适时机调用):
- `setAuthToken(token: string | null): void`
- `setClientId(clientId: string | null): void`
- `setLocation(latitude: number | null, longitude: number | null): void`
- `setLanguage(language: string | null): void`
- `getRequestContext(): RequestContext`
默认值策略:
- `language`:如果未显式设置,尝试读取 `src/i18n/index.ts``getCurrentLocale()`(读取失败则不注入 language header
#### 2.2 Axios 实例创建与默认配置
- `baseURL``import.meta.env.VITE_API_BASE_URL`
- 若缺失:直接抛出清晰错误(提示需要配置 baseURL
- `timeout`:可选 `import.meta.env.VITE_API_TIMEOUT_MS`,缺失则默认 15000
#### 2.3 请求拦截器header 注入)
组装 headers 规则:
- 合并顺序:`默认headers < 上下文headers < 调用方options.headers`
- `Authorization`:仅当 token 存在时注入 `Bearer <token>`;当 `options.skipAuth === true` 时跳过
- `clientId`:存在则注入
- `X-Latitude` / `X-Longitude`:存在则注入(数值转字符串)
- `language`:存在则注入
#### 2.4 响应处理(业务码 + 错误归一化)
1. 正常响应:
- 若响应体符合 `ApiResponse<T>``code === 0`:返回整个 `ApiResponse<T>`
- 若响应体符合 `ApiResponse<T>``code !== 0`:抛出 `NormalizedError(kind="business", code, message, response)`
2. 异常响应axios error
-`response.status`:抛 `NormalizedError(kind="http", httpStatus, response)`
-`response`:抛 `NormalizedError(kind="network")`
对外导出(建议最小集合):
- `export async function request<T>(config, options?: RequestOptions): Promise<ApiResponse<T>>`
- 可选:`export async function requestData<T>(...): Promise<T>`(内部调用 request 并返回 `data`,用于未来更干净的调用风格)
### 3) 文档输出到 `docs/`
新增目录:`docs/`
新增文档:`docs/request.md`(必须包含):
- 环境变量约定:`VITE_API_BASE_URL``VITE_API_TIMEOUT_MS`(可选)
- 上下文写入时机:
- 登录成功:`setAuthToken(token)`
- 应用初始化:`setClientId(clientId)`
- 定位成功:`setLocation(lat, lng)`
- 语言切换:`setLanguage(locale)`(或依赖默认读取 i18n
- 使用方式:
- 旧代码风格兼容:`const res = await request<T>(); res.data...`
- 新代码推荐:`const data = await requestData<T>()`
- 错误处理示例:区分 business/http/network/unknown 并给出上层建议策略
## 历史遗留问题清单(独立梳理,方便逐个替换)
说明:以下均为“当前仓库扫描可证实”的问题点,按模块引用位置列出,便于你后续按优先级逐个替换/补齐。
### A. `@/request/api/*` 悬空引用13 个文件)
- `src/pages/quick/index.vue`
- `src/components/Feedback/index.vue`
- `src/components/CreateServiceOrder/index.vue`
- `src/pages/service/order/components/OrderCard/index.vue`
- `src/pages/booking/components/FooterSection/index.vue`
- `src/pages/goods/index.vue`
- `src/pages/order/order/components/FooterSection/index.vue`
- `src/pages/quick/components/Tabs/index.vue`
- `src/pages/order/order/list.vue`
- `src/pages/service/order/index.vue`
- `src/pages/booking/index.vue`
- `src/pages/login/index.vue`
- `src/pages/order/order/detail.vue`
建议后续替换策略:
1. 先确定“这些 API 模块的真实来源”(是否在其它分支/其它仓库/尚未迁入)。
2. 如果确认不会迁回,则逐文件把 `@/request/api/*` 替换为基于 `src/utils/request.ts` 的真实调用(需要你提供具体 URL/参数约定)。
### B. `@/utils` 目录级导入缺失6 个文件)
当前仓库没有 `src/utils/index.*`,但以下文件在导入 `@/utils`
- `src/pages/quick/index.vue`
- `src/pages/booking/components/FooterSection/index.vue`
- `src/pages/goods/index.vue`
- `src/pages/order/order/components/FooterSection/index.vue`
- `src/pages/booking/index.vue`
- `src/pages/home/index.vue`
### C. `@/store` 与实际目录 `src/stores/` 命名不一致6 个文件)
- `src/components/ImageSwiper/index.vue`
- `src/pages/quick/components/Card/index.vue`
- `src/pages/goods/album/index.vue`
- `src/pages/goods/index.vue`
- `src/pages/booking/index.vue`
- `src/pages/home/index.vue`
### D. `@/hooks/*` 缺失3 个文件)
- `src/components/SwipeCards/index.vue`
- `src/pages/login/index.vue`
- `src/pages/home/index.vue`
### E. `@/constant/*` 缺失6 个文件)
- `src/components/ModuleTitle/index.vue`
- `src/components/Feedback/index.vue`
- `src/components/SurveyQuestionnaire/index.vue`
- `src/components/CreateServiceOrder/index.vue`
- `src/pages/booking/index.vue`
- `src/pages/login/index.vue`
### F. `src/utils/request.ts`(空文件 + 疑似拼写问题)
- 该文件当前为空,且命名疑似应为 `requests``request`
- 建议后续统一策略:保留/替换/删除前先全仓搜索确认是否在其它分支被引用
## Verification执行阶段你手动确认运行
你在实现完成后手动执行:
- `yarn typecheck`
- `yarn build`
- 如有用例:`yarn test`
验收标准:
- `src/utils/request.ts` + `src/shared/request-types.ts` 编译通过
- 发起请求时能注入 headersAuthorization/clientId/X-Latitude/X-Longitude/language
- `code !== 0` 时抛出稳定结构的错误对象(上层可根据 kind 做统一处理)