接手一个 3 年老项目,打开 api/axios.ts 看到 800 行代码------拦截器里塞了鉴权、品牌切换、错误提示、日志、重试......每次改一个逻辑都怕影响别的。
我把这个文件丢给 AI,让它帮我重新设计架构。最终方案:洋葱模型,每个关注点一个中间件,互不干扰。
原始状态
scss
axios.ts (800行)
├── 请求拦截器 (200行)
│ ├── 鉴权 token 注入
│ ├── brandId 注入
│ ├── 环境判断
│ ├── 请求日志
│ └── 特殊 URL 处理
├── 响应拦截器 (400行)
│ ├── 登录过期处理
│ ├── 权限不足处理
│ ├── 网络错误处理
│ ├── 业务错误码映射
│ ├── 错误弹窗逻辑
│ └── 重试逻辑
└── 工具函数 (200行)
改一行都心惊肉跳。
AI 给出的分层设计
yaml
请求生命周期(洋葱模型):
请求方向 →
┌─────────────────────────────────────────────┐
│ Layer 1: Auth(鉴权) │
│ ┌───────────────────────────────────────┐ │
│ │ Layer 2: BrandId(品牌注入) │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ Layer 3: ErrorHandler(错误) │ │ │
│ │ │ ┌───────────────────────────┐ │ │ │
│ │ │ │ 实际网络请求 │ │ │ │
│ │ │ └───────────────────────────┘ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
← 响应方向
每一层只管一件事,新增需求加一层,删除需求去掉一层,不影响其他层。
关键代码:拦截器拆分
改造前(混在一起):
typescript
axios.interceptors.request.use((config) => {
// 50行鉴权逻辑
const token = getToken()
if (token) config.headers.Authorization = token
// 30行品牌逻辑
const brandId = getBrandId()
if (brandId) config.headers['X-Brand-Id'] = brandId
// 20行环境逻辑
if (process.env.API_ENV === 'test') { ... }
// ...更多
return config
})
改造后(各管各的):
typescript
// interceptors/auth.ts
export const authInterceptor = {
request: (config: AxiosRequestConfig) => {
const token = getToken()
if (token) {
config.headers.Authorization = token
}
return config
},
responseError: (error: AxiosError) => {
if (error.response?.status === 401) {
handleLogout()
}
return Promise.reject(error)
},
}
// interceptors/brandId.ts
export const brandIdInterceptor = {
request: (config: AxiosRequestConfig) => {
const brandId = getBrandId()
if (brandId) {
config.headers['X-Brand-Id'] = brandId
}
return config
},
}
// interceptors/errorHandler.ts
export const errorHandlerInterceptor = {
responseError: (error: AxiosError) => {
const { status, data } = error.response || {}
const msg = ERROR_CODE_MAP[data?.code] || '网络异常'
message.error(msg)
return Promise.reject(error)
},
}
注册:
typescript
// api/axios.ts(现在只有 30 行)
const instance = axios.create({ baseURL: PROXY_URL, timeout: 15000 })
const interceptors = [
authInterceptor,
brandIdInterceptor,
errorHandlerInterceptor,
]
interceptors.forEach(({ request, response, responseError }) => {
if (request) instance.interceptors.request.use(request)
if (response) instance.interceptors.response.use(response)
if (responseError) instance.interceptors.response.use(undefined, responseError)
})
export default instance
AI 在这个过程中做了什么
arduino
我的输入:
├── "这是我的 axios.ts,帮我重构"
├── "要求:每个关注点分离,可独立测试"
└── "保持对外 API 不变,调用方零改动"
AI 的输出:
├── 架构建议(洋葱模型 vs 管道模式 vs 装饰器模式)
├── 每个拦截器的独立文件
├── 注册逻辑
└── 一个我没想到的点:拦截器执行顺序说明
拦截器顺序的坑
AI 特别提醒了一个 axios 的行为:
ini
请求拦截器:后注册的先执行(栈结构)
响应拦截器:先注册的先执行(队列结构)
所以注册顺序要反着想:
interceptors = [auth, brandId, errorHandler]
实际请求执行顺序:errorHandler → brandId → auth → [网络] → auth → brandId → errorHandler
这个如果不注意,鉴权失败时的错误处理顺序会出问题。AI 在设计阶段就帮我规避了。
对外接口不变
改造前怎么用的,改造后还是怎么用:
typescript
// 业务层调用------零改动
import request from '@/api/axios'
export const getStoreList = (params: StoreListParams) =>
request.get('/store/list', { params })
这就是重构的核心原则:内部随便改,外部无感知。
收益
arduino
改造前:
├── 800 行单文件,改一行可能影响全部
├── 无法单独测试某个拦截逻辑
├── 新人看完需要 2h 才能理解
└── 加新功能(如请求加密)需要在 3 个地方改
改造后:
├── 主文件 30 行,每个拦截器 30-50 行
├── 每个拦截器可独立 mock 测试
├── 新人 10min 理解整体架构
└── 加新功能 = 加一个文件 + 注册一行
什么时候该重构请求层
值得重构:
├── 拦截器超过 100 行
├── 多个不相关逻辑写在同一个拦截器
├── 改一个功能总担心影响其他
└── 新人入职搞不懂请求层做了什么
不需要的:
├── 项目小(拦截器 <50 行)
├── 逻辑简单(只有 token 注入 + 错误提示)
└── 没人维护的遗留项目
💬 你们项目的请求层是什么状态?有没有类似的"上帝文件"想重构但不敢动?
🔗 完整 Skills 源码已开源 :github.com/sleepyccat/...,欢迎 Star ⭐ 和 PR。