vue3版本+TS(typescript)+简单封装api 配置反向代理

vue3版本+TS(typescript)+简单封装api 配置反向代理

一、背景与问题

在现代前端开发中,API调用和反向代理配置是核心需求。对于Vue3+TypeScript项目,直接使用原生fetch或axios存在以下痛点:

  1. 类型安全缺失:原始API调用缺少类型定义,导致运行时错误难以排查
  2. 重复代码:每个API请求都需要重复处理请求头、超时、错误处理等逻辑
  3. 跨域限制:开发环境需要配置反向代理解决跨域问题
  4. 环境差异:开发/生产环境需要不同的API地址和代理配置

本文将深入探讨如何通过TypeScript封装API接口,结合Vue3的组合式API特性,实现统一的请求管理,同时配置反向代理解决开发环境的跨域问题。

二、基本原理

1. TypeScript类型系统优势

TypeScript的类型系统可以为API接口提供强类型保障。通过定义接口类型,可以实现以下效果:

interface User {
  id: number
  name: string
  email: string
}

在API调用时,可以确保返回数据符合预期类型:

const user: User = await getUser(1)

2. Axios封装原理

通过创建axios实例并配置统一参数,可以实现:

  • 自动添加请求头(如Authorization)
  • 统一错误处理
  • 请求/响应拦截器
  • 超时控制

3. 反向代理原理

开发环境使用反向代理解决跨域问题,核心原理是:

  • 客户端请求 → 代理服务器 → 后端服务器
  • 代理服务器转发请求并返回响应
  • 避免浏览器同源策略限制

三、环境准备

1. 项目依赖

npm init -y
npm install -D typescript ts-node vite @vitejs/plugin-vue
npm install axios

2. TypeScript配置

创建tsconfig.json:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"]
}

四、核心实现

1. API封装(核心代码)

创建src/api/index.ts:

// src/api/index.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'

// 定义请求配置类型
interface ApiConfig {
  baseURL: string
  timeout?: number
  headers?: Record<string, string>
}

// 创建axios实例
const createApi = (config: ApiConfig): AxiosInstance => {
  const api = axios.create(config)
  
  // 请求拦截器
  api.interceptors.request.use(
    (config: AxiosRequestConfig) => {
      // 添加请求头
      config.headers = {
        ...config.headers,
        'Content-Type': 'application/json',
        'X-Requested-With': 'XMLHttpRequest'
      }
      return config
    },
    (error: any) => {
      return Promise.reject(error)
    }
  )

  // 响应拦截器
  api.interceptors.response.use(
    (response: AxiosResponse) => {
      // 处理响应数据
      return response.data
    },
    (error: any) => {
      // 统一错误处理
      const message = error.response?.data?.message || '服务器错误'
      console.error('API Error:', message)
      return Promise.reject(message)
    }
  )

  return api
}

// 配置不同环境的API
export const api = {
  development: createApi({
    baseURL: 'http://localhost:3000/api',
    timeout: 5000,
    headers: {
      'Authorization': 'Bearer dev_token'
    }
  }),
  production: createApi({
    baseURL: 'https://api.example.com',
    timeout: 10000,
    headers: {
      'Authorization': 'Bearer prod_token'
    }
  })
}

2. 反向代理配置(Vite开发服务器)

在vite.config.ts中配置代理:

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': resolve(__dirname, './src')
    }
  },
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000', // 后端服务地址
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

3. 类型定义(接口规范)

创建src/types/api.ts:

// src/types/api.ts
export interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

五、完整案例

1. 项目结构

project-root/
├── src/
│   ├── api/
│   │   └── index.ts
│   ├── types/
│   │   └── api.ts
│   └── main.ts
│   └── App.vue
├── vite.config.ts
├── tsconfig.json
└── package.json

2. 使用示例(组件中调用API)

<!-- src/App.vue -->
<template>
  <div>
    <button @click="fetchData">获取数据</button>
    <div v-if="data">{{ data.name }}</div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { api } from '@/api'

const data = ref(null)
const fetchData = async () => {
  try {
    const res: ApiResponse<{ id: number, name: string }> = await api.development.get('/users/1')
    data.value = res.data
  } catch (error) {
    console.error('请求失败:', error)
  }
}
</script>

3. 后端接口示例(假设后端服务)

// 后端示例(Node.js + Express)
app.get('/api/users/1', (req, res) => {
  res.json({
    code: 200,
    message: '成功',
    data: {
      id: 1,
      name: '张三'
    }
  })
})

六、源码解析

1. API封装关键点

  • 拦截器机制:通过拦截器统一处理请求和响应,避免重复代码
  • 类型安全:使用泛型和类型断言确保数据类型正确
  • 环境区分:根据环境选择不同的API地址和认证信息

2. 反向代理配置细节

  • changeOrigin: true:确保代理服务器能正确处理跨域请求
  • rewrite函数:将/api路径重写为后端服务的根路径
  • 代理配置只在开发环境生效,生产环境应使用Nginx等专业服务器

七、进阶使用

1. 动态代理配置

在vite.config.ts中支持多环境配置:

export default defineConfig(({ mode }) => {
  const proxyConfig = {
    '/api': {
      target: 'http://localhost:3000',
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/api/, '')
    }
  }

  if (mode === 'production') {
    proxyConfig['/api'] = {
      target: 'https://api.example.com',
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/api/, '')
    }
  }

  return {
    // ...其他配置
    server: {
      proxy: proxyConfig
    }
  }
})

2. 接口分类管理

按业务模块划分API接口:

// src/api/user.ts
export const getUser = (id: number) => api.development.get(`/users/${id}`)
export const createUser = (data: { name: string }) => api.development.post('/users', data)

3. 请求重试机制

添加请求重试逻辑:

import { retry } from 'rxjs/operators'

api.interceptors.request.use(config => {
  return retry(3, 1000)(config) // 重试3次,间隔1秒
})

八、性能与工程实践

1. 性能优化

  • 请求合并:通过axios.all合并多个请求
  • 缓存机制:对高频接口添加缓存
  • 并发控制:使用axios.CancelToken管理并发请求

2. 安全风险

  • CORS配置:确保后端正确设置CORS头
  • 敏感信息:避免在代理配置中暴露敏感信息
  • HTTPS强制:生产环境强制使用HTTPS

3. 方案对比

方案优点缺点
Vite代理配置简单,开发便捷仅适用于开发环境
Nginx代理支持生产环境,功能强大配置复杂,需要额外部署
服务端代理更安全,可控制请求需要后端配合

九、常见问题与踩坑

1. 代理配置不生效

错误场景:

// 错误配置
proxy: {
  '/api': 'http://localhost:3000'
}

解决办法:

// 正确配置
proxy: {
  '/api': {
    target: 'http://localhost:3000',
    changeOrigin: true
  }
}

2. 类型断言错误

错误场景:

const res = await api.get('/users/1') // 缺少类型定义

解决办法:

const res: ApiResponse<{ id: number, name: string }> = await api.get('/users/1')

3. 跨域请求失败

错误场景:

// 后端未配置CORS
res.setHeader('Access-Control-Allow-Origin', '*')

解决办法:

// 后端配置CORS
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5000')

十、最佳实践

  1. 统一接口管理:所有API请求通过统一的api对象调用
  2. 类型安全:为每个接口定义明确的类型
  3. 环境区分:根据环境变量区分开发/生产环境
  4. 错误处理:统一的错误处理逻辑,避免重复代码
  5. 代理配置:开发环境使用Vite代理,生产环境使用Nginx
  6. 性能优化:对高频接口添加缓存,对慢接口添加重试机制
  7. 安全防护:生产环境强制使用HTTPS,配置CORS头

十一、总结

通过Vue3+TypeScript的API封装和反向代理配置,我们可以实现:

  • 更安全的API调用
  • 更高效的错误处理
  • 更清晰的代码结构
  • 更方便的环境管理

这种方案特别适合以下场景:

  • 中小型项目需要快速搭建API调用体系
  • 需要强类型保障的前端项目
  • 开发环境需要解决跨域问题的项目

但需注意避免以下情况:

  • 生产环境使用Vite代理(需部署Nginx)
  • 在复杂业务场景中未合理划分API接口
  • 忽略安全配置导致接口暴露

在实际开发中,建议结合项目规模和团队规范选择合适方案,合理使用TypeScript的类型系统和axios的拦截器机制,构建可维护、可扩展的API调用体系。

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日