我用 AI 重写了项目的请求层,从 800 行"面条代码"变成 3 层洋葱模型

接手一个 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。

相关推荐
全栈弄潮儿2 小时前
不要先问“用哪个 AI”,先盘点你的开发工作流
aigc·openai·ai编程
杨杨杨大侠3 小时前
大模型的权重到底怎么用?拆开一个 token 的生成过程
aigc·openai·ai编程
吴佳浩 Alben4 小时前
Agent 怎么做自动化评测?构建端到端的 Agent Evaluation 体系
人工智能·语言模型·架构·自动化·ai编程
宿6744 小时前
vue3-包管理器
前端·vue.js
小虎AI生活4 小时前
从四大模型一周连发看企业 AI 落地,为什么 95% 的试点不赚钱
ai编程
@PHARAOH5 小时前
WHAT - Remix 入门和基本实践:理解两套产物
前端·remix
孟健5 小时前
Gemini 3.8 Flash 没涨价,干活却贵了 40%?
ai编程
mayaairi5 小时前
Vue2 生命周期完全指南:从创建到销毁的8个钩子函数
前端·javascript·vue.js
xy34536 小时前
axure9.0 如何打造一个计时器(简单版)
前端·ui·html·axure·原型·产品设计
IMPYLH6 小时前
HTML 的 <pre> 元素
前端·javascript·html